diff options
428 files changed, 32247 insertions, 9976 deletions
@@ -315,7 +315,6 @@ fwbase_dirs_to_document := \ fwbase_dirs_to_document += core/config/sdk # include definition of libcore_to_document -# These are relative to libcore include $(LOCAL_PATH)/../../libcore/Docs.mk non_base_dirs := \ @@ -324,8 +323,7 @@ non_base_dirs := \ # These are relative to frameworks/base dirs_to_document := \ $(fwbase_dirs_to_document) \ - $(non_base_dirs) \ - $(addprefix ../../libcore/, $(libcore_to_document)) + $(non_base_dirs) html_dirs := \ $(FRAMEWORKS_BASE_SUBDIRS) \ @@ -334,7 +332,8 @@ html_dirs := \ # These are relative to frameworks/base framework_docs_LOCAL_SRC_FILES := \ $(call find-other-java-files, $(dirs_to_document)) \ - $(call find-other-html-files, $(html_dirs)) + $(call find-other-html-files, $(html_dirs)) \ + $(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore)) # This is used by ide.mk as the list of source files that are # always included. diff --git a/libs/hwui/utils/GenerationCache.h b/GenerationCache.h index 42e6d9b..42e6d9b 100644 --- a/libs/hwui/utils/GenerationCache.h +++ b/GenerationCache.h @@ -241287,7 +241287,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -241774,7 +241774,7 @@ synchronized="true" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -241840,7 +241840,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -241961,7 +241961,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -242330,7 +242330,7 @@ synchronized="true" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="l" type="android.webkit.WebSettings.LayoutAlgorithm"> @@ -242408,7 +242408,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="enabled" type="boolean"> @@ -242603,7 +242603,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="view" type="boolean"> @@ -242731,7 +242731,7 @@ abstract="false" static="true" final="true" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <method name="valueOf" @@ -243417,7 +243417,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -243439,7 +243439,7 @@ synchronized="false" static="true" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -243463,7 +243463,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -243474,7 +243474,7 @@ synchronized="false" static="true" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -244011,7 +244011,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="b" type="android.os.Bundle"> @@ -244067,7 +244067,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="b" type="android.os.Bundle"> @@ -244222,7 +244222,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="listener" type="android.webkit.WebView.PictureListener"> @@ -244494,7 +244494,7 @@ abstract="true" static="true" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <method name="onNewPicture" @@ -244504,7 +244504,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="view" type="android.webkit.WebView"> diff --git a/api/current.xml b/api/current.xml index b8b11fe..555f804 100644 --- a/api/current.xml +++ b/api/current.xml @@ -9068,6 +9068,17 @@ visibility="public" > </field> +<field name="state_hovered" + type="int" + transient="false" + volatile="false" + value="16843620" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="state_last" type="int" transient="false" @@ -22045,6 +22056,32 @@ <parameter name="useLogo" type="boolean"> </parameter> </method> +<method name="setIcon" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="resId" type="int"> +</parameter> +</method> +<method name="setIcon" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="icon" type="android.graphics.drawable.Drawable"> +</parameter> +</method> <method name="setListNavigationCallbacks" return="void" abstract="true" @@ -22060,6 +22097,32 @@ <parameter name="callback" type="android.app.ActionBar.OnNavigationListener"> </parameter> </method> +<method name="setLogo" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="resId" type="int"> +</parameter> +</method> +<method name="setLogo" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="logo" type="android.graphics.drawable.Drawable"> +</parameter> +</method> <method name="setNavigationMode" return="void" abstract="true" @@ -31442,6 +31505,25 @@ <parameter name="exit" type="int"> </parameter> </method> +<method name="setCustomAnimations" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="enter" type="int"> +</parameter> +<parameter name="exit" type="int"> +</parameter> +<parameter name="popEnter" type="int"> +</parameter> +<parameter name="popExit" type="int"> +</parameter> +</method> <method name="setTransition" return="android.app.FragmentTransaction" abstract="true" @@ -86678,6 +86760,17 @@ <parameter name="texName" type="int"> </parameter> </constructor> +<method name="getTimestamp" + return="long" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getTransformMatrix" return="void" abstract="false" @@ -93334,6 +93427,17 @@ visibility="public" > </field> +<field name="TYPE_AMBIENT_TEMPERATURE" + type="int" + transient="false" + volatile="false" + value="13" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="TYPE_GRAVITY" type="int" transient="false" @@ -93440,7 +93544,7 @@ value="7" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -105715,6 +105819,23 @@ deprecated="not deprecated" visibility="public" > +<parameter name="uri" type="java.lang.String"> +</parameter> +<parameter name="headers" type="java.util.Map<java.lang.String, java.lang.String>"> +</parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +</method> +<method name="setDataSource" + return="void" + abstract="false" + native="true" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> <parameter name="fd" type="java.io.FileDescriptor"> </parameter> <parameter name="offset" type="long"> @@ -105802,6 +105923,17 @@ visibility="public" > </field> +<field name="METADATA_KEY_BITRATE" + type="int" + transient="false" + volatile="false" + value="20" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="METADATA_KEY_CD_TRACK_NUMBER" type="int" transient="false" @@ -105879,6 +106011,28 @@ visibility="public" > </field> +<field name="METADATA_KEY_HAS_AUDIO" + type="int" + transient="false" + volatile="false" + value="16" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="METADATA_KEY_HAS_VIDEO" + type="int" + transient="false" + volatile="false" + value="17" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="METADATA_KEY_MIMETYPE" type="int" transient="false" @@ -105912,6 +106066,28 @@ visibility="public" > </field> +<field name="METADATA_KEY_VIDEO_HEIGHT" + type="int" + transient="false" + volatile="false" + value="19" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="METADATA_KEY_VIDEO_WIDTH" + type="int" + transient="false" + volatile="false" + value="18" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="METADATA_KEY_WRITER" type="int" transient="false" @@ -153927,6 +154103,17 @@ visibility="public" > </method> +<method name="getTitleRes" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getView" return="android.view.View" abstract="false" @@ -154820,6 +155007,25 @@ <parameter name="target" type="java.util.List<android.preference.PreferenceActivity.Header>"> </parameter> </method> +<method name="onBuildStartFragmentIntent" + return="android.content.Intent" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fragmentName" type="java.lang.String"> +</parameter> +<parameter name="args" type="android.os.Bundle"> +</parameter> +<parameter name="titleRes" type="int"> +</parameter> +<parameter name="shortTitleRes" type="int"> +</parameter> +</method> <method name="onGetInitialHeader" return="android.preference.PreferenceActivity.Header" abstract="false" @@ -155024,6 +155230,29 @@ <parameter name="resultRequestCode" type="int"> </parameter> </method> +<method name="startWithFragment" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fragmentName" type="java.lang.String"> +</parameter> +<parameter name="args" type="android.os.Bundle"> +</parameter> +<parameter name="resultTo" type="android.app.Fragment"> +</parameter> +<parameter name="resultRequestCode" type="int"> +</parameter> +<parameter name="titleRes" type="int"> +</parameter> +<parameter name="shortTitleRes" type="int"> +</parameter> +</method> <method name="switchToHeader" return="void" abstract="false" @@ -155085,6 +155314,28 @@ visibility="public" > </field> +<field name="EXTRA_SHOW_FRAGMENT_SHORT_TITLE" + type="java.lang.String" + transient="false" + volatile="false" + value="":android:show_fragment_short_title"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_SHOW_FRAGMENT_TITLE" + type="java.lang.String" + transient="false" + volatile="false" + value="":android:show_fragment_title"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="HEADER_ID_UNDEFINED" type="long" transient="false" @@ -201869,6 +202120,175 @@ </parameter> </method> </class> +<class name="CorrectionSpan" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.text.ParcelableSpan"> +</implements> +<constructor name="CorrectionSpan" + type="android.text.style.CorrectionSpan" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="suggestions" type="java.lang.String[]"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</constructor> +<constructor name="CorrectionSpan" + type="android.text.style.CorrectionSpan" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="locale" type="java.util.Locale"> +</parameter> +<parameter name="suggestions" type="java.lang.String[]"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</constructor> +<constructor name="CorrectionSpan" + type="android.text.style.CorrectionSpan" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="locale" type="java.util.Locale"> +</parameter> +<parameter name="suggestions" type="java.lang.String[]"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +<parameter name="originalString" type="java.lang.String"> +</parameter> +</constructor> +<constructor name="CorrectionSpan" + type="android.text.style.CorrectionSpan" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="src" type="android.os.Parcel"> +</parameter> +</constructor> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getFlags" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getLocale" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getOriginalString" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getSpanTypeId" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getSuggestions" + return="java.lang.String[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dest" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="FLAG_VERBATIM" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <class name="DrawableMarginSpan" extends="java.lang.Object" abstract="false" @@ -213161,6 +213581,17 @@ visibility="public" > </field> +<field name="KEYCODE_3D_MODE" + type="int" + transient="false" + volatile="false" + value="206" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="KEYCODE_4" type="int" transient="false" @@ -214316,6 +214747,17 @@ visibility="public" > </field> +<field name="KEYCODE_LANGUAGE_SWITCH" + type="int" + transient="false" + volatile="false" + value="204" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="KEYCODE_LEFT_BRACKET" type="int" transient="false" @@ -214338,6 +214780,17 @@ visibility="public" > </field> +<field name="KEYCODE_MANNER_MODE" + type="int" + transient="false" + volatile="false" + value="205" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="KEYCODE_MEDIA_CLOSE" type="int" transient="false" @@ -218226,6 +218679,28 @@ visibility="public" > </field> +<field name="ACTION_HOVER_ENTER" + type="int" + transient="false" + volatile="false" + value="9" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_HOVER_EXIT" + type="int" + transient="false" + volatile="false" + value="10" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ACTION_HOVER_MOVE" type="int" transient="false" @@ -220799,7 +221274,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="ev" type="android.view.MotionEvent"> +<parameter name="event" type="android.view.MotionEvent"> </parameter> </method> <method name="clear" @@ -223049,6 +223524,17 @@ visibility="public" > </method> +<method name="isHovered" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="isInEditMode" return="boolean" abstract="false" @@ -223524,6 +224010,19 @@ <parameter name="event" type="android.view.MotionEvent"> </parameter> </method> +<method name="onHoverEvent" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="event" type="android.view.MotionEvent"> +</parameter> +</method> <method name="onKeyDown" return="boolean" abstract="false" @@ -224564,6 +225063,19 @@ <parameter name="horizontalScrollBarEnabled" type="boolean"> </parameter> </method> +<method name="setHovered" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="hovered" type="boolean"> +</parameter> +</method> <method name="setId" return="void" abstract="false" @@ -233520,7 +234032,7 @@ value="500" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -241287,7 +241799,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -241774,7 +242286,7 @@ synchronized="true" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -241840,7 +242352,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -241961,7 +242473,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -242330,7 +242842,7 @@ synchronized="true" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="l" type="android.webkit.WebSettings.LayoutAlgorithm"> @@ -242408,7 +242920,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="enabled" type="boolean"> @@ -242603,7 +243115,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="view" type="boolean"> @@ -242731,7 +243243,7 @@ abstract="false" static="true" final="true" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <method name="valueOf" @@ -243417,7 +243929,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -243439,7 +243951,7 @@ synchronized="false" static="true" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -243463,7 +243975,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -243474,7 +243986,7 @@ synchronized="false" static="true" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > </method> @@ -244011,7 +244523,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="b" type="android.os.Bundle"> @@ -244067,7 +244579,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="b" type="android.os.Bundle"> @@ -244222,7 +244734,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="listener" type="android.webkit.WebView.PictureListener"> @@ -244494,7 +245006,7 @@ abstract="true" static="true" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <method name="onNewPicture" @@ -244504,7 +245016,7 @@ synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > <parameter name="view" type="android.webkit.WebView"> @@ -264382,9 +264894,9 @@ </parameter> <parameter name="start" type="int"> </parameter> -<parameter name="before" type="int"> +<parameter name="lengthBefore" type="int"> </parameter> -<parameter name="after" type="int"> +<parameter name="lengthAfter" type="int"> </parameter> </method> <method name="onTextContextMenuItem" @@ -267156,7 +267668,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="arg0" type="T"> +<parameter name="t" type="T"> </parameter> </method> </interface> diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 2b89759..a00a212 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -22,7 +22,7 @@ LOCAL_SHARED_LIBRARIES := \ libskia \ libEGL \ libGLESv1_CM \ - libsurfaceflinger_client + libgui LOCAL_C_INCLUDES := \ $(call include-path-for, corecg graphics) diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk index 400a36b..ca8008b 100644 --- a/cmds/screencap/Android.mk +++ b/cmds/screencap/Android.mk @@ -10,7 +10,7 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libskia \ libui \ - libsurfaceflinger_client + libgui LOCAL_MODULE:= screencap diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk index 1b13dd9..e9642f7 100644 --- a/cmds/stagefright/Android.mk +++ b/cmds/stagefright/Android.mk @@ -8,7 +8,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libstagefright libmedia libutils libbinder libstagefright_foundation \ - libskia libsurfaceflinger_client libgui + libskia libgui LOCAL_C_INCLUDES:= \ $(JNI_H_INCLUDE) \ @@ -107,7 +107,7 @@ LOCAL_SRC_FILES:= \ stream.cpp \ LOCAL_SHARED_LIBRARIES := \ - libstagefright liblog libutils libbinder libsurfaceflinger_client \ + libstagefright liblog libutils libbinder libgui \ libstagefright_foundation libmedia LOCAL_C_INCLUDES:= \ @@ -132,7 +132,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libstagefright liblog libutils libbinder libstagefright_foundation \ - libmedia libsurfaceflinger_client libcutils libui + libmedia libgui libcutils libui LOCAL_C_INCLUDES:= \ $(JNI_H_INCLUDE) \ diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index fc5fac6..a9e84d7 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -160,6 +160,66 @@ public abstract class ActionBar { public abstract void setCustomView(int resId); /** + * Set the icon to display in the 'home' section of the action bar. + * The action bar will use an icon specified by its style or the + * activity icon by default. + * + * Whether the home section shows an icon or logo is controlled + * by the display option {@link #DISPLAY_USE_LOGO}. + * + * @param resId Resource ID of a drawable to show as an icon. + * + * @see #setDisplayUseLogoEnabled(boolean) + * @see #setDisplayShowHomeEnabled(boolean) + */ + public abstract void setIcon(int resId); + + /** + * Set the icon to display in the 'home' section of the action bar. + * The action bar will use an icon specified by its style or the + * activity icon by default. + * + * Whether the home section shows an icon or logo is controlled + * by the display option {@link #DISPLAY_USE_LOGO}. + * + * @param icon Drawable to show as an icon. + * + * @see #setDisplayUseLogoEnabled(boolean) + * @see #setDisplayShowHomeEnabled(boolean) + */ + public abstract void setIcon(Drawable icon); + + /** + * Set the logo to display in the 'home' section of the action bar. + * The action bar will use a logo specified by its style or the + * activity logo by default. + * + * Whether the home section shows an icon or logo is controlled + * by the display option {@link #DISPLAY_USE_LOGO}. + * + * @param resId Resource ID of a drawable to show as a logo. + * + * @see #setDisplayUseLogoEnabled(boolean) + * @see #setDisplayShowHomeEnabled(boolean) + */ + public abstract void setLogo(int resId); + + /** + * Set the logo to display in the 'home' section of the action bar. + * The action bar will use a logo specified by its style or the + * activity logo by default. + * + * Whether the home section shows an icon or logo is controlled + * by the display option {@link #DISPLAY_USE_LOGO}. + * + * @param logo Drawable to show as a logo. + * + * @see #setDisplayUseLogoEnabled(boolean) + * @see #setDisplayShowHomeEnabled(boolean) + */ + public abstract void setLogo(Drawable logo); + + /** * Set the adapter and navigation callback for list navigation mode. * * The supplied adapter will provide views for the expanded list as well as diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index bd83762..3e5b21f 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -45,6 +45,7 @@ import android.graphics.Canvas; import android.net.IConnectivityManager; import android.net.Proxy; import android.net.ProxyProperties; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -3427,6 +3428,14 @@ public final class ActivityThread { Process.setArgV0(data.processName); android.ddm.DdmHandleAppName.setAppName(data.processName); + // If the app is Honeycomb MR1 or earlier, switch its AsyncTask + // implementation to use the pool executor. Normally, we use the + // serialized executor as the default. This has to happen in the + // main thread so the main looper is set right. + if (data.appInfo.targetSdkVersion <= 12) { + AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + /* * Before spawning a new process, reset the time zone to be the system time zone. * This needs to be done because the system time zone could have changed after the diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 1d217f0..850f56a 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -43,7 +43,7 @@ final class BackStackState implements Parcelable { if (op.removed != null) numRemoved += op.removed.size(); op = op.next; } - mOps = new int[bse.mNumOp*5 + numRemoved]; + mOps = new int[bse.mNumOp*7 + numRemoved]; if (!bse.mAddToBackStack) { throw new IllegalStateException("Not on back stack"); @@ -56,6 +56,8 @@ final class BackStackState implements Parcelable { mOps[pos++] = op.fragment.mIndex; mOps[pos++] = op.enterAnim; mOps[pos++] = op.exitAnim; + mOps[pos++] = op.popEnterAnim; + mOps[pos++] = op.popExitAnim; if (op.removed != null) { final int N = op.removed.size(); mOps[pos++] = N; @@ -101,6 +103,8 @@ final class BackStackState implements Parcelable { op.fragment = f; op.enterAnim = mOps[pos++]; op.exitAnim = mOps[pos++]; + op.popEnterAnim = mOps[pos++]; + op.popExitAnim = mOps[pos++]; final int N = mOps[pos++]; if (N > 0) { op.removed = new ArrayList<Fragment>(N); @@ -177,6 +181,8 @@ final class BackStackRecord extends FragmentTransaction implements Fragment fragment; int enterAnim; int exitAnim; + int popEnterAnim; + int popExitAnim; ArrayList<Fragment> removed; } @@ -185,6 +191,8 @@ final class BackStackRecord extends FragmentTransaction implements int mNumOp; int mEnterAnim; int mExitAnim; + int mPopEnterAnim; + int mPopExitAnim; int mTransition; int mTransitionStyle; boolean mAddToBackStack; @@ -241,6 +249,11 @@ final class BackStackRecord extends FragmentTransaction implements writer.print(prefix); writer.print("enterAnim="); writer.print(op.enterAnim); writer.print(" exitAnim="); writer.println(op.exitAnim); } + if (op.popEnterAnim != 0 || op.popExitAnim != 0) { + writer.print(prefix); + writer.print("popEnterAnim="); writer.print(op.popEnterAnim); + writer.print(" popExitAnim="); writer.println(op.popExitAnim); + } if (op.removed != null && op.removed.size() > 0) { for (int i=0; i<op.removed.size(); i++) { writer.print(innerPrefix); @@ -299,6 +312,8 @@ final class BackStackRecord extends FragmentTransaction implements } op.enterAnim = mEnterAnim; op.exitAnim = mExitAnim; + op.popEnterAnim = mPopEnterAnim; + op.popExitAnim = mPopExitAnim; mNumOp++; } @@ -402,8 +417,15 @@ final class BackStackRecord extends FragmentTransaction implements } public FragmentTransaction setCustomAnimations(int enter, int exit) { + return setCustomAnimations(enter, exit, 0, 0); + } + + public FragmentTransaction setCustomAnimations(int enter, int exit, + int popEnter, int popExit) { mEnterAnim = enter; mExitAnim = exit; + mPopEnterAnim = popEnter; + mPopExitAnim = popExit; return this; } @@ -593,6 +615,7 @@ final class BackStackRecord extends FragmentTransaction implements switch (op.cmd) { case OP_ADD: { Fragment f = op.fragment; + f.mNextAnim = op.popExitAnim; f.mImmediateActivity = null; mManager.removeFragment(f, FragmentManagerImpl.reverseTransit(mTransition), @@ -600,6 +623,7 @@ final class BackStackRecord extends FragmentTransaction implements } break; case OP_REPLACE: { Fragment f = op.fragment; + f.mNextAnim = op.popExitAnim; f.mImmediateActivity = null; mManager.removeFragment(f, FragmentManagerImpl.reverseTransit(mTransition), @@ -607,6 +631,7 @@ final class BackStackRecord extends FragmentTransaction implements if (op.removed != null) { for (int i=0; i<op.removed.size(); i++) { Fragment old = op.removed.get(i); + old.mNextAnim = op.popEnterAnim; f.mImmediateActivity = mManager.mActivity; mManager.addFragment(old, false); } @@ -614,16 +639,19 @@ final class BackStackRecord extends FragmentTransaction implements } break; case OP_REMOVE: { Fragment f = op.fragment; + f.mNextAnim = op.popEnterAnim; f.mImmediateActivity = mManager.mActivity; mManager.addFragment(f, false); } break; case OP_HIDE: { Fragment f = op.fragment; + f.mNextAnim = op.popEnterAnim; mManager.showFragment(f, FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle); } break; case OP_SHOW: { Fragment f = op.fragment; + f.mNextAnim = op.popExitAnim; mManager.hideFragment(f, FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle); } break; diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java index 0cc774d..68600b3 100644 --- a/core/java/android/app/FragmentTransaction.java +++ b/core/java/android/app/FragmentTransaction.java @@ -116,10 +116,20 @@ public abstract class FragmentTransaction { /** * Set specific animation resources to run for the fragments that are - * entering and exiting in this transaction. + * entering and exiting in this transaction. These animations will not be + * played when popping the back stack. */ public abstract FragmentTransaction setCustomAnimations(int enter, int exit); - + + /** + * Set specific animation resources to run for the fragments that are + * entering and exiting in this transaction. The <code>popEnter</code> + * and <code>popExit</code> animations will be played for enter/exit + * operations specifically when popping the back stack. + */ + public abstract FragmentTransaction setCustomAnimations(int enter, int exit, + int popEnter, int popExit); + /** * Select a standard transition animation for this transaction. May be * one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN}, diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java index 4c2d123..83f3891 100644 --- a/core/java/android/database/sqlite/SQLiteCursor.java +++ b/core/java/android/database/sqlite/SQLiteCursor.java @@ -241,7 +241,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { mColumnNameMap = null; mQuery = query; - query.mDatabase.lock(); + query.mDatabase.lock(query.mSql); try { // Setup the list of columns int columnCount = mQuery.columnCountLocked(); @@ -419,7 +419,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { // since we need to use a different database connection handle, // re-compile the query try { - db.lock(); + db.lock(mQuery.mSql); } catch (IllegalStateException e) { // for backwards compatibility, just return false Log.w(TAG, "requery() failed " + e.getMessage(), e); diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 90a5b5d..2f2b4eb 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -230,9 +230,23 @@ public class SQLiteDatabase extends SQLiteClosable { private static int sQueryLogTimeInMillis = 0; // lazily initialized private static final int QUERY_LOG_SQL_LENGTH = 64; private static final String COMMIT_SQL = "COMMIT;"; + private static final String BEGIN_SQL = "BEGIN;"; private final Random mRandom = new Random(); + /** the last non-commit/rollback sql statement in a transaction */ + // guarded by 'this' private String mLastSqlStatement = null; + synchronized String getLastSqlStatement() { + return mLastSqlStatement; + } + + synchronized void setLastSqlStatement(String sql) { + mLastSqlStatement = sql; + } + + /** guarded by {@link #mLock} */ + private long mTransStartTime; + // String prefix for slow database query EventLog records that show // lock acquistions of the database. /* package */ static final String GET_LOCK_LOG_PREFIX = "GETLOCK:"; @@ -386,11 +400,16 @@ public class SQLiteDatabase extends SQLiteClosable { * * @see #unlock() */ - /* package */ void lock() { - lock(false); + /* package */ void lock(String sql) { + lock(sql, false); + } + + /* pachage */ void lock() { + lock(null, false); } + private static final long LOCK_WAIT_PERIOD = 30L; - private void lock(boolean forced) { + private void lock(String sql, boolean forced) { // make sure this method is NOT being called from a 'synchronized' method if (Thread.holdsLock(this)) { Log.w(TAG, "don't lock() while in a synchronized method"); @@ -398,6 +417,7 @@ public class SQLiteDatabase extends SQLiteClosable { verifyDbIsOpen(); if (!forced && !mLockingEnabled) return; boolean done = false; + long timeStart = SystemClock.uptimeMillis(); while (!done) { try { // wait for 30sec to acquire the lock @@ -420,6 +440,9 @@ public class SQLiteDatabase extends SQLiteClosable { mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); } } + if (sql != null) { + logTimeStat(sql, timeStart, GET_LOCK_LOG_PREFIX); + } } private static class DatabaseReentrantLock extends ReentrantLock { DatabaseReentrantLock(boolean fair) { @@ -444,7 +467,11 @@ public class SQLiteDatabase extends SQLiteClosable { * @see #unlockForced() */ private void lockForced() { - lock(true); + lock(null, true); + } + + private void lockForced(String sql) { + lock(sql, true); } /** @@ -612,7 +639,7 @@ public class SQLiteDatabase extends SQLiteClosable { private void beginTransaction(SQLiteTransactionListener transactionListener, boolean exclusive) { verifyDbIsOpen(); - lockForced(); + lockForced(BEGIN_SQL); boolean ok = false; try { // If this thread already had the lock then get out @@ -635,6 +662,7 @@ public class SQLiteDatabase extends SQLiteClosable { } else { execSQL("BEGIN IMMEDIATE;"); } + mTransStartTime = SystemClock.uptimeMillis(); mTransactionListener = transactionListener; mTransactionIsSuccessful = true; mInnerTransactionIsSuccessful = false; @@ -698,6 +726,8 @@ public class SQLiteDatabase extends SQLiteClosable { Log.i(TAG, "PRAGMA wal_Checkpoint done"); } } + // log the transaction time to the Eventlog. + logTimeStat(getLastSqlStatement(), mTransStartTime, COMMIT_SQL); } else { try { execSQL("ROLLBACK;"); @@ -1855,24 +1885,7 @@ public class SQLiteDatabase extends SQLiteClosable { * @throws SQLException if the SQL string is invalid */ public void execSQL(String sql) throws SQLException { - int stmtType = DatabaseUtils.getSqlStatementType(sql); - if (stmtType == DatabaseUtils.STATEMENT_ATTACH) { - disableWriteAheadLogging(); - } - long timeStart = SystemClock.uptimeMillis(); - logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX); executeSql(sql, null); - - if (stmtType == DatabaseUtils.STATEMENT_ATTACH) { - mHasAttachedDbs = true; - } - // Log commit statements along with the most recently executed - // SQL statement for disambiguation. - if (stmtType == DatabaseUtils.STATEMENT_COMMIT) { - logTimeStat(mLastSqlStatement, timeStart, COMMIT_SQL); - } else { - logTimeStat(sql, timeStart, null); - } } /** @@ -1926,19 +1939,19 @@ public class SQLiteDatabase extends SQLiteClosable { } private int executeSql(String sql, Object[] bindArgs) throws SQLException { - long timeStart = SystemClock.uptimeMillis(); - int n; + if (DatabaseUtils.getSqlStatementType(sql) == DatabaseUtils.STATEMENT_ATTACH) { + disableWriteAheadLogging(); + mHasAttachedDbs = true; + } SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs); try { - n = statement.executeUpdateDelete(); + return statement.executeUpdateDelete(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; } finally { statement.close(); } - logTimeStat(sql, timeStart); - return n; } @Override @@ -2027,12 +2040,7 @@ public class SQLiteDatabase extends SQLiteClosable { logTimeStat(sql, beginMillis, null); } - /* package */ void logTimeStat(String sql, long beginMillis, String prefix) { - // Keep track of the last statement executed here, as this is - // the common funnel through which all methods of hitting - // libsqlite eventually flow. - mLastSqlStatement = sql; - + private void logTimeStat(String sql, long beginMillis, String prefix) { // Sample fast queries in proportion to the time taken. // Quantize the % first, so the logged sampling probability // exactly equals the actual sampling rate for this query. @@ -2059,7 +2067,6 @@ public class SQLiteDatabase extends SQLiteClosable { if (prefix != null) { sql = prefix + sql; } - if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH); // ActivityThread.currentPackageName() only returns non-null if the diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java index de2fca9..a5e762e 100644 --- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java +++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java @@ -42,7 +42,7 @@ public class SQLiteDirectCursorDriver implements SQLiteCursorDriver { SQLiteQuery query = null; try { - mDatabase.lock(); + mDatabase.lock(mSql); mDatabase.closePendingStatements(); query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs); diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java index 88246e8..89552dc 100644 --- a/core/java/android/database/sqlite/SQLiteProgram.java +++ b/core/java/android/database/sqlite/SQLiteProgram.java @@ -105,12 +105,9 @@ public abstract class SQLiteProgram extends SQLiteClosable { case DatabaseUtils.STATEMENT_SELECT: mStatementType = n | STATEMENT_CACHEABLE | STATEMENT_USE_POOLED_CONN; break; - case DatabaseUtils.STATEMENT_ATTACH: case DatabaseUtils.STATEMENT_BEGIN: case DatabaseUtils.STATEMENT_COMMIT: case DatabaseUtils.STATEMENT_ABORT: - case DatabaseUtils.STATEMENT_DDL: - case DatabaseUtils.STATEMENT_UNPREPARED: mStatementType = n | STATEMENT_DONT_PREPARE; break; default: @@ -353,13 +350,10 @@ public abstract class SQLiteProgram extends SQLiteClosable { /* package */ void compileAndbindAllArgs() { if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) { - // no need to prepare this SQL statement - if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { - if (mBindArgs != null) { - throw new IllegalArgumentException("no need to pass bindargs for this sql :" + - mSql); - } + if (mBindArgs != null) { + throw new IllegalArgumentException("Can't pass bindargs for this sql :" + mSql); } + // no need to prepare this SQL statement return; } if (nStatement == 0) { diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java index e9e0172..dc882d9 100644 --- a/core/java/android/database/sqlite/SQLiteQuery.java +++ b/core/java/android/database/sqlite/SQLiteQuery.java @@ -70,9 +70,8 @@ public class SQLiteQuery extends SQLiteProgram { */ /* package */ int fillWindow(CursorWindow window, int maxRead, int lastPos) { + mDatabase.lock(mSql); long timeStart = SystemClock.uptimeMillis(); - mDatabase.lock(); - mDatabase.logTimeStat(mSql, timeStart, SQLiteDatabase.GET_LOCK_LOG_PREFIX); try { acquireReference(); try { diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index c76cc6c..ff973a7 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -80,7 +80,8 @@ public class SQLiteStatement extends SQLiteProgram */ public int executeUpdateDelete() { try { - long timeStart = acquireAndLock(WRITE); + saveSqlAsLastSqlStatement(); + acquireAndLock(WRITE); int numChanges = 0; if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) { // since the statement doesn't have to be prepared, @@ -90,7 +91,6 @@ public class SQLiteStatement extends SQLiteProgram } else { numChanges = native_execute(); } - mDatabase.logTimeStat(mSql, timeStart); return numChanges; } finally { releaseAndUnlock(); @@ -108,15 +108,22 @@ public class SQLiteStatement extends SQLiteProgram */ public long executeInsert() { try { - long timeStart = acquireAndLock(WRITE); - long lastInsertedRowId = native_executeInsert(); - mDatabase.logTimeStat(mSql, timeStart); - return lastInsertedRowId; + saveSqlAsLastSqlStatement(); + acquireAndLock(WRITE); + return native_executeInsert(); } finally { releaseAndUnlock(); } } + private void saveSqlAsLastSqlStatement() { + if (((mStatementType & SQLiteProgram.STATEMENT_TYPE_MASK) == + DatabaseUtils.STATEMENT_UPDATE) || + (mStatementType & SQLiteProgram.STATEMENT_TYPE_MASK) == + DatabaseUtils.STATEMENT_BEGIN) { + mDatabase.setLastSqlStatement(mSql); + } + } /** * Execute a statement that returns a 1 by 1 table with a numeric value. * For example, SELECT COUNT(*) FROM table; @@ -199,7 +206,7 @@ public class SQLiteStatement extends SQLiteProgram * <li>if the SQL statement is an update, start transaction if not already in one. * otherwise, get lock on the database</li> * <li>acquire reference on this object</li> - * <li>and then return the current time _before_ the database lock was acquired</li> + * <li>and then return the current time _after_ the database lock was acquired</li> * </ul> * <p> * This method removes the duplicate code from the other public @@ -243,7 +250,7 @@ public class SQLiteStatement extends SQLiteProgram } // do I have database lock? if not, grab it. if (!mDatabase.isDbLockedByCurrentThread()) { - mDatabase.lock(); + mDatabase.lock(mSql); mState = LOCK_ACQUIRED; } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 97f0e1b..e525c95 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -374,6 +374,12 @@ public class Camera { * The preview surface texture may not otherwise change while preview is * running. * + * The timestamps provided by {@link SurfaceTexture#getTimestamp()} for a + * SurfaceTexture set as the preview texture have an unspecified zero point, + * and cannot be directly compared between different cameras or different + * instances of the same camera, or across multiple runs of the same + * program. + * * @param surfaceTexture the {@link SurfaceTexture} to which the preview * images are to be sent or null to remove the current preview surface * texture @@ -410,8 +416,9 @@ public class Camera { /** * Starts capturing and drawing preview frames to the screen. - * Preview will not actually start until a surface is supplied with - * {@link #setPreviewDisplay(SurfaceHolder)}. + * Preview will not actually start until a surface is supplied + * with {@link #setPreviewDisplay(SurfaceHolder)} or + * {@link #setPreviewTexture(SurfaceTexture)}. * * <p>If {@link #setPreviewCallback(Camera.PreviewCallback)}, * {@link #setOneShotPreviewCallback(Camera.PreviewCallback)}, or diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index f2b907b..a4ba3bd 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -66,7 +66,14 @@ public class Sensor { /** A constant describing a pressure sensor type */ public static final int TYPE_PRESSURE = 6; - /** A constant describing a temperature sensor type */ + /** + * A constant describing a temperature sensor type + * + * @deprecated use + * {@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE + * Sensor.TYPE_AMBIENT_TEMPERATURE} instead. + */ + @Deprecated public static final int TYPE_TEMPERATURE = 7; /** @@ -97,6 +104,9 @@ public class Sensor { */ public static final int TYPE_ROTATION_VECTOR = 11; + /** A constant describing an ambient temperature sensor type */ + public static final int TYPE_AMBIENT_TEMPERATURE = 13; + /** * A constant describing all sensor types. */ diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index 78d7991..91f0098 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -305,6 +305,14 @@ public class SensorEvent { * positive in the counter-clockwise direction). * </p> * + * <h4>{@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE Sensor.TYPE_AMBIENT_TEMPERATURE}: + * </h4> + * + * <ul> + * <p> + * values[0]: ambient (room) temperature in degree Celsius. + * </ul> + * * @see SensorEvent * @see GeomagneticField */ diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java new file mode 100644 index 0000000..df5fdd0 --- /dev/null +++ b/core/java/android/net/EthernetDataTracker.java @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2010 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.net; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.DhcpInfoInternal; +import android.net.LinkAddress; +import android.net.LinkCapabilities; +import android.net.LinkProperties; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkStateTracker; +import android.net.NetworkUtils; +import android.os.Handler; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import java.net.InetAddress; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * This class tracks the data connection associated with Ethernet + * This is a singleton class and an instance will be created by + * ConnectivityService. + * @hide + */ +public class EthernetDataTracker implements NetworkStateTracker { + private static final String NETWORKTYPE = "ETHERNET"; + private static final String TAG = "Ethernet"; + + private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); + private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); + private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); + private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); + + private LinkProperties mLinkProperties; + private LinkCapabilities mLinkCapabilities; + private NetworkInfo mNetworkInfo; + private InterfaceObserver mInterfaceObserver; + + /* For sending events to connectivity service handler */ + private Handler mCsHandler; + private Context mContext; + + private static EthernetDataTracker sInstance; + private static String mIface = ""; + + private static class InterfaceObserver extends INetworkManagementEventObserver.Stub { + private EthernetDataTracker mTracker; + + InterfaceObserver(EthernetDataTracker tracker) { + super(); + mTracker = tracker; + } + + public void interfaceLinkStatusChanged(String iface, boolean up) { + Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down")); + } + + public void interfaceAdded(String iface) { + mTracker.interfaceAdded(iface); + } + + public void interfaceRemoved(String iface) { + mTracker.interfaceRemoved(iface); + } + } + + private EthernetDataTracker() { + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, ""); + mLinkProperties = new LinkProperties(); + mLinkCapabilities = new LinkCapabilities(); + + mNetworkInfo.setIsAvailable(false); + setTeardownRequested(false); + } + + private void interfaceAdded(String iface) { + if (!iface.matches("eth\\d")) + return; + + Log.d(TAG, "Adding " + iface); + + synchronized(mIface) { + if(!mIface.isEmpty()) + return; + mIface = iface; + } + + mNetworkInfo.setIsAvailable(true); + Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); + msg.sendToTarget(); + + runDhcp(); + } + + private void interfaceRemoved(String iface) { + if (!iface.equals(mIface)) + return; + + Log.d(TAG, "Removing " + iface); + + NetworkUtils.stopDhcp(mIface); + + mLinkProperties.clear(); + mNetworkInfo.setIsAvailable(false); + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); + + Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); + msg.sendToTarget(); + + msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); + msg.sendToTarget(); + + mIface = ""; + } + + private void runDhcp() { + Thread dhcpThread = new Thread(new Runnable() { + public void run() { + DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); + if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) { + Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); + return; + } + mLinkProperties = dhcpInfoInternal.makeLinkProperties(); + mLinkProperties.setInterfaceName(mIface); + + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); + Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); + msg.sendToTarget(); + } + }); + dhcpThread.start(); + } + + public static synchronized EthernetDataTracker getInstance() { + if (sInstance == null) sInstance = new EthernetDataTracker(); + return sInstance; + } + + public Object Clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + public void setTeardownRequested(boolean isRequested) { + mTeardownRequested.set(isRequested); + } + + public boolean isTeardownRequested() { + return mTeardownRequested.get(); + } + + /** + * Begin monitoring connectivity + */ + public void startMonitoring(Context context, Handler target) { + mContext = context; + mCsHandler = target; + + // register for notifications from NetworkManagement Service + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); + mInterfaceObserver = new InterfaceObserver(this); + try { + service.registerObserver(mInterfaceObserver); + } catch (RemoteException e) { + Log.e(TAG, "Could not register InterfaceObserver " + e); + } + } + + /** + * Disable connectivity to a network + * TODO: do away with return value after making MobileDataStateTracker async + */ + public boolean teardown() { + mTeardownRequested.set(true); + NetworkUtils.stopDhcp(mIface); + return true; + } + + /** + * Re-enable connectivity to a network after a {@link #teardown()}. + */ + public boolean reconnect() { + mTeardownRequested.set(false); + runDhcp(); + return true; + } + + /** + * Turn the wireless radio off for a network. + * @param turnOn {@code true} to turn the radio on, {@code false} + */ + public boolean setRadio(boolean turnOn) { + return true; + } + + /** + * @return true - If are we currently tethered with another device. + */ + public synchronized boolean isAvailable() { + return mNetworkInfo.isAvailable(); + } + + /** + * Tells the underlying networking system that the caller wants to + * begin using the named feature. The interpretation of {@code feature} + * is completely up to each networking implementation. + * @param feature the name of the feature to be used + * @param callingPid the process ID of the process that is issuing this request + * @param callingUid the user ID of the process that is issuing this request + * @return an integer value representing the outcome of the request. + * The interpretation of this value is specific to each networking + * implementation+feature combination, except that the value {@code -1} + * always indicates failure. + * TODO: needs to go away + */ + public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) { + return -1; + } + + /** + * Tells the underlying networking system that the caller is finished + * using the named feature. The interpretation of {@code feature} + * is completely up to each networking implementation. + * @param feature the name of the feature that is no longer needed. + * @param callingPid the process ID of the process that is issuing this request + * @param callingUid the user ID of the process that is issuing this request + * @return an integer value representing the outcome of the request. + * The interpretation of this value is specific to each networking + * implementation+feature combination, except that the value {@code -1} + * always indicates failure. + * TODO: needs to go away + */ + public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) { + return -1; + } + + /** + * @param enabled + */ + public void setDataEnable(boolean enabled) { + Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled); + } + + /** + * Check if private DNS route is set for the network + */ + public boolean isPrivateDnsRouteSet() { + return mPrivateDnsRouteSet.get(); + } + + /** + * Set a flag indicating private DNS route is set + */ + public void privateDnsRouteSet(boolean enabled) { + mPrivateDnsRouteSet.set(enabled); + } + + /** + * Fetch NetworkInfo for the network + */ + public synchronized NetworkInfo getNetworkInfo() { + return mNetworkInfo; + } + + /** + * Fetch LinkProperties for the network + */ + public synchronized LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); + } + + /** + * A capability is an Integer/String pair, the capabilities + * are defined in the class LinkSocket#Key. + * + * @return a copy of this connections capabilities, may be empty but never null. + */ + public LinkCapabilities getLinkCapabilities() { + return new LinkCapabilities(mLinkCapabilities); + } + + /** + * Fetch default gateway address for the network + */ + public int getDefaultGatewayAddr() { + return mDefaultGatewayAddr.get(); + } + + /** + * Check if default route is set + */ + public boolean isDefaultRouteSet() { + return mDefaultRouteSet.get(); + } + + /** + * Set a flag indicating default route is set for the network + */ + public void defaultRouteSet(boolean enabled) { + mDefaultRouteSet.set(enabled); + } + + /** + * Return the system properties name associated with the tcp buffer sizes + * for this network. + */ + public String getTcpBufferSizesPropName() { + return "net.tcp.buffersize.wifi"; + } +} diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index f8f8a29..3bf64b2 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -17,18 +17,12 @@ package android.net; import android.os.SystemProperties; -import android.util.Config; import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; -import java.security.GeneralSecurityException; import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.Certificate; import java.security.cert.X509Certificate; import javax.net.SocketFactory; @@ -40,7 +34,6 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl; @@ -128,7 +121,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0 * for none. The socket timeout is reset to 0 after the handshake. - * @param cache The {@link SSLClientSessionCache} to use, or null for no cache. + * @param cache The {@link SSLSessionCache} to use, or null for no cache. * @return a new SSLSocketFactory with the specified parameters */ public static SSLSocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) { @@ -144,7 +137,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0 * for none. The socket timeout is reset to 0 after the handshake. - * @param cache The {@link SSLClientSessionCache} to use, or null for no cache. + * @param cache The {@link SSLSessionCache} to use, or null for no cache. * @return an insecure SSLSocketFactory with the specified parameters */ public static SSLSocketFactory getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache) { @@ -157,12 +150,11 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0 * for none. The socket timeout is reset to 0 after the handshake. - * @param cache The {@link SSLClientSessionCache} to use, or null for no cache. + * @param cache The {@link SSLSessionCache} to use, or null for no cache. * @return a new SocketFactory with the specified parameters */ public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory( - int handshakeTimeoutMillis, - SSLSessionCache cache) { + int handshakeTimeoutMillis, SSLSessionCache cache) { return new org.apache.http.conn.ssl.SSLSocketFactory( new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true)); } diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java index d77e9d9..84765a5 100644 --- a/core/java/android/net/http/HttpsConnection.java +++ b/core/java/android/net/http/HttpsConnection.java @@ -289,11 +289,9 @@ public class HttpsConnection extends Connection { } else { // if we do not have a proxy, we simply connect to the host try { - sslSock = (SSLSocket) getSocketFactory().createSocket(); - + sslSock = (SSLSocket) getSocketFactory().createSocket( + mHost.getHostName(), mHost.getPort()); sslSock.setSoTimeout(SOCKET_TIMEOUT); - sslSock.connect(new InetSocketAddress(mHost.getHostName(), - mHost.getPort())); } catch(IOException e) { if (sslSock != null) { sslSock.close(); diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java index 1803604..64bba54 100644 --- a/core/java/android/os/AsyncTask.java +++ b/core/java/android/os/AsyncTask.java @@ -153,7 +153,6 @@ public abstract class AsyncTask<Params, Progress, Result> { private static final int MAXIMUM_POOL_SIZE = 128; private static final int KEEP_ALIVE = 1; - private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); @@ -183,6 +182,7 @@ public abstract class AsyncTask<Params, Progress, Result> { private static final InternalHandler sHandler = new InternalHandler(); + private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture; @@ -240,6 +240,11 @@ public abstract class AsyncTask<Params, Progress, Result> { sHandler.getLooper(); } + /** @hide */ + public static void setDefaultExecutor(Executor exec) { + sDefaultExecutor = exec; + } + /** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ @@ -496,7 +501,7 @@ public abstract class AsyncTask<Params, Progress, Result> { * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. */ public final AsyncTask<Params, Progress, Result> execute(Params... params) { - return executeOnExecutor(THREAD_POOL_EXECUTOR, params); + return executeOnExecutor(sDefaultExecutor, params); } /** @@ -559,7 +564,7 @@ public abstract class AsyncTask<Params, Progress, Result> { * a simple Runnable object. */ public static void execute(Runnable runnable) { - THREAD_POOL_EXECUTOR.execute(runnable); + sDefaultExecutor.execute(runnable); } /** diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java index f82702a..e8148f7 100644 --- a/core/java/android/os/MemoryFile.java +++ b/core/java/android/os/MemoryFile.java @@ -28,7 +28,7 @@ import java.io.OutputStream; * MemoryFile is a wrapper for the Linux ashmem driver. * MemoryFiles are backed by shared memory, which can be optionally * set to be purgeable. - * Purgeable files may have their contents reclaimed by the kernel + * Purgeable files may have their contents reclaimed by the kernel * in low memory conditions (only if allowPurging is set to true). * After a file is purged, attempts to read or write the file will * cause an IOException to be thrown. @@ -126,7 +126,7 @@ public class MemoryFile close(); } } - + /** * Returns the length of the memory file. * @@ -190,7 +190,7 @@ public class MemoryFile * @return number of bytes read. * @throws IOException if the memory file has been purged or deactivated. */ - public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count) + public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count) throws IOException { if (isDeactivated()) { throw new IOException("Can't read from deactivated memory file."); @@ -330,6 +330,7 @@ public class MemoryFile @Override public void write(byte buffer[], int offset, int count) throws IOException { writeBytes(buffer, offset, mOffset, count); + mOffset += count; } @Override diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index efb8415..57fdb0c 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -97,7 +97,8 @@ import android.util.Log; * </tbody> * </table> * - * + * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK} + * permission in an {@code <uses-permission>} element of the application's manifest. */ public class PowerManager { @@ -188,8 +189,11 @@ public class PowerManager /** * Class lets you say that you need to have the device on. - * - * <p>Call release when you are done and don't need the lock anymore. + * <p> + * Call release when you are done and don't need the lock anymore. + * <p> + * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK} + * permission in an {@code <uses-permission>} element of the application's manifest. */ public class WakeLock { diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index 7d37e5b..5e1be21 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -89,6 +89,7 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis private int mOrder = DEFAULT_ORDER; private CharSequence mTitle; + private int mTitleRes; private CharSequence mSummary; /** * mIconResId is overridden by mIcon, if mIcon is specified. @@ -214,6 +215,7 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis break; case com.android.internal.R.styleable.Preference_title: + mTitleRes = a.getResourceId(attr, 0); mTitle = a.getString(attr); break; @@ -582,6 +584,7 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis */ public void setTitle(CharSequence title) { if (title == null && mTitle != null || title != null && !title.equals(mTitle)) { + mTitleRes = 0; mTitle = title; notifyChanged(); } @@ -595,9 +598,21 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis */ public void setTitle(int titleResId) { setTitle(mContext.getString(titleResId)); + mTitleRes = titleResId; } /** + * Returns the title resource ID of this Preference. If the title did + * not come from a resource, 0 is returned. + * + * @return The title resource. + * @see #setTitle(int) + */ + public int getTitleRes() { + return mTitleRes; + } + + /** * Returns the title of this Preference. * * @return The title. diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index ad0bc84..15d5898 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -132,13 +132,28 @@ public abstract class PreferenceActivity extends ListActivity implements /** * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, - * this extra can also be specify to supply a Bundle of arguments to pass + * this extra can also be specified to supply a Bundle of arguments to pass * to that fragment when it is instantiated during the initial creation * of PreferenceActivity. */ public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":android:show_fragment_args"; /** + * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, + * this extra can also be specify to supply the title to be shown for + * that fragment. + */ + public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":android:show_fragment_title"; + + /** + * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, + * this extra can also be specify to supply the short title to be shown for + * that fragment. + */ + public static final String EXTRA_SHOW_FRAGMENT_SHORT_TITLE + = ":android:show_fragment_short_title"; + + /** * When starting this activity, the invoking Intent can contain this extra * boolean that the header list should not be displayed. This is most often * used in conjunction with {@link #EXTRA_SHOW_FRAGMENT} to launch @@ -488,7 +503,12 @@ public abstract class PreferenceActivity extends ListActivity implements protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(com.android.internal.R.layout.preference_list_content); + if (getResources().getConfiguration().isLayoutSizeAtLeast( + Configuration.SCREENLAYOUT_SIZE_LARGE)) { + setContentView(com.android.internal.R.layout.preference_list_content_large); + } else { + setContentView(com.android.internal.R.layout.preference_list_content); + } mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer); mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs_frame); @@ -496,6 +516,8 @@ public abstract class PreferenceActivity extends ListActivity implements mSinglePane = hidingHeaders || !onIsMultiPane(); String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT); Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); + int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0); + int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0); if (savedInstanceState != null) { // We are restarting from a previous saved state; used that to @@ -516,6 +538,12 @@ public abstract class PreferenceActivity extends ListActivity implements // new fragment mode, but don't need to compute and show // the headers. switchToHeader(initialFragment, initialArguments); + if (initialTitle != 0) { + CharSequence initialTitleStr = getText(initialTitle); + CharSequence initialShortTitleStr = initialShortTitle != 0 + ? getText(initialShortTitle) : null; + showBreadCrumbs(initialTitleStr, initialShortTitleStr); + } } else { // We need to try to build the headers. @@ -557,7 +585,12 @@ public abstract class PreferenceActivity extends ListActivity implements } else { // If there are no headers, we are in the old "just show a screen // of preferences" mode. - setContentView(com.android.internal.R.layout.preference_list_content_single); + if (getResources().getConfiguration().isLayoutSizeAtLeast( + Configuration.SCREENLAYOUT_SIZE_LARGE)) { + setContentView(com.android.internal.R.layout.preference_list_content_single_large); + } else { + setContentView(com.android.internal.R.layout.preference_list_content_single); + } mListFooter = (FrameLayout) findViewById(com.android.internal.R.id.list_footer); mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs); mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE); @@ -942,7 +975,8 @@ public abstract class PreferenceActivity extends ListActivity implements /** * Called when the user selects an item in the header list. The default - * implementation will call either {@link #startWithFragment(String, Bundle, Fragment, int)} + * implementation will call either + * {@link #startWithFragment(String, Bundle, Fragment, int, int, int)} * or {@link #switchToHeader(Header)} as appropriate. * * @param header The header that was selected. @@ -951,7 +985,14 @@ public abstract class PreferenceActivity extends ListActivity implements public void onHeaderClick(Header header, int position) { if (header.fragment != null) { if (mSinglePane) { - startWithFragment(header.fragment, header.fragmentArguments, null, 0); + int titleRes = header.breadCrumbTitleRes; + int shortTitleRes = header.breadCrumbShortTitleRes; + if (titleRes == 0) { + titleRes = header.titleRes; + shortTitleRes = 0; + } + startWithFragment(header.fragment, header.fragmentArguments, null, 0, + titleRes, shortTitleRes); } else { switchToHeader(header); } @@ -961,6 +1002,41 @@ public abstract class PreferenceActivity extends ListActivity implements } /** + * Called by {@link #startWithFragment(String, Bundle, Fragment, int, int, int)} when + * in single-pane mode, to build an Intent to launch a new activity showing + * the selected fragment. The default implementation constructs an Intent + * that re-launches the current activity with the appropriate arguments to + * display the fragment. + * + * @param fragmentName The name of the fragment to display. + * @param args Optional arguments to supply to the fragment. + * @param titleRes Optional resource ID of title to show for this item. + * @param titleRes Optional resource ID of short title to show for this item. + * @return Returns an Intent that can be launched to display the given + * fragment. + */ + public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args, + int titleRes, int shortTitleRes) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClass(this, getClass()); + intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName); + intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); + intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, titleRes); + intent.putExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, shortTitleRes); + intent.putExtra(EXTRA_NO_HEADERS, true); + return intent; + } + + /** + * Like {@link #startWithFragment(String, Bundle, Fragment, int, int, int)} + * but uses a 0 titleRes. + */ + public void startWithFragment(String fragmentName, Bundle args, + Fragment resultTo, int resultRequestCode) { + startWithFragment(fragmentName, args, resultTo, resultRequestCode, 0, 0); + } + + /** * Start a new instance of this activity, showing only the given * preference fragment. When launched in this mode, the header list * will be hidden and the given preference fragment will be instantiated @@ -968,14 +1044,18 @@ public abstract class PreferenceActivity extends ListActivity implements * * @param fragmentName The name of the fragment to display. * @param args Optional arguments to supply to the fragment. + * @param resultTo Option fragment that should receive the result of + * the activity launch. + * @param resultRequestCode If resultTo is non-null, this is the request + * code in which to report the result. + * @param titleRes Resource ID of string to display for the title of + * this set of preferences. + * @param titleRes Resource ID of string to display for the short title of + * this set of preferences. */ public void startWithFragment(String fragmentName, Bundle args, - Fragment resultTo, int resultRequestCode) { - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setClass(this, getClass()); - intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName); - intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); - intent.putExtra(EXTRA_NO_HEADERS, true); + Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes) { + Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes); if (resultTo == null) { startActivity(intent); } else { @@ -992,16 +1072,16 @@ public abstract class PreferenceActivity extends ListActivity implements if (mFragmentBreadCrumbs == null) { View crumbs = findViewById(android.R.id.title); // For screens with a different kind of title, don't create breadcrumbs. - if (!(crumbs instanceof FragmentBreadCrumbs)) return; - mFragmentBreadCrumbs = (FragmentBreadCrumbs) findViewById(android.R.id.title); + try { + mFragmentBreadCrumbs = (FragmentBreadCrumbs)crumbs; + } catch (ClassCastException e) { + return; + } if (mFragmentBreadCrumbs == null) { - mFragmentBreadCrumbs = new FragmentBreadCrumbs(this); - ActionBar actionBar = getActionBar(); - if (actionBar != null) { - actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, - ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM); - actionBar.setCustomView(mFragmentBreadCrumbs); + if (title != null) { + setTitle(title); } + return; } mFragmentBreadCrumbs.setMaxVisible(2); mFragmentBreadCrumbs.setActivity(this); @@ -1169,7 +1249,7 @@ public abstract class PreferenceActivity extends ListActivity implements public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes, CharSequence titleText, Fragment resultTo, int resultRequestCode) { if (mSinglePane) { - startWithFragment(fragmentClass, args, resultTo, resultRequestCode); + startWithFragment(fragmentClass, args, resultTo, resultRequestCode, titleRes, 0); } else { Fragment f = Fragment.instantiate(this, fragmentClass, args); if (resultTo != null) { @@ -1215,7 +1295,8 @@ public abstract class PreferenceActivity extends ListActivity implements @Override public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) { - startPreferencePanel(pref.getFragment(), pref.getExtras(), 0, pref.getTitle(), null, 0); + startPreferencePanel(pref.getFragment(), pref.getExtras(), pref.getTitleRes(), + pref.getTitle(), null, 0); return true; } diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java index 4e22ba0..7511e14 100644 --- a/core/java/android/preference/PreferenceFragment.java +++ b/core/java/android/preference/PreferenceFragment.java @@ -20,6 +20,7 @@ import android.app.Activity; import android.app.Fragment; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -151,8 +152,14 @@ public abstract class PreferenceFragment extends Fragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(com.android.internal.R.layout.preference_list_fragment, - container, false); + if (getResources().getConfiguration().isLayoutSizeAtLeast( + Configuration.SCREENLAYOUT_SIZE_LARGE)) { + return inflater.inflate(com.android.internal.R.layout.preference_list_fragment_large, + container, false); + } else { + return inflater.inflate(com.android.internal.R.layout.preference_list_fragment, + container, false); + } } @Override diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index b59421e..bb8d874 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -166,7 +166,6 @@ public final class MediaStore { * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri * value of EXTRA_OUTPUT. * @see #EXTRA_OUTPUT - * @see #EXTRA_VIDEO_QUALITY */ public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; @@ -181,6 +180,9 @@ public final class MediaStore { * written to the standard location for videos, and the Uri of that location will be * returned in the data field of the Uri. * @see #EXTRA_OUTPUT + * @see #EXTRA_VIDEO_QUALITY + * @see #EXTRA_SIZE_LIMIT + * @see #EXTRA_DURATION_LIMIT */ public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE"; diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index d2d2557..6ff9f0e 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -90,12 +90,18 @@ public final class Telephony { public static final String PERSON_ID = "person"; /** - * The date the message was sent + * The date the message was received * <P>Type: INTEGER (long)</P> */ public static final String DATE = "date"; /** + * The date the message was sent + * <P>Type: INTEGER (long)</P> + */ + public static final String DATE_SENT = "date_sent"; + + /** * Has the message been read * <P>Type: INTEGER (boolean)</P> */ @@ -650,12 +656,18 @@ public final class Telephony { public static final int MESSAGE_BOX_OUTBOX = 4; /** - * The date the message was sent. + * The date the message was received. * <P>Type: INTEGER (long)</P> */ public static final String DATE = "date"; /** + * The date the message was sent. + * <P>Type: INTEGER (long)</P> + */ + public static final String DATE_SENT = "date_sent"; + + /** * The box which the message belong to, for example, MESSAGE_BOX_INBOX. * <P>Type: INTEGER</P> */ diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 186af70..95830ec 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -44,6 +44,8 @@ import java.util.Locale; */ public class TextToSpeech { + private static final String TAG = "TextToSpeech"; + /** * Denotes a successful operation. */ @@ -579,29 +581,16 @@ public class TextToSpeech { mITts.addSpeech(mPackageName, text, packagename, resourceId); return SUCCESS; } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addSpeech", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addSpeech", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addSpeech", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addSpeech", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addSpeech", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addSpeech", e); } return ERROR; } } - /** * Adds a mapping between a string of text and a sound file. Using this, it * is possible to add custom pronounciations for a string of text. @@ -626,23 +615,11 @@ public class TextToSpeech { mITts.addSpeechFile(mPackageName, text, filename); return SUCCESS; } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addSpeech", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addSpeech", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addSpeech", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addSpeech", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addSpeech", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addSpeech", e); } return ERROR; } @@ -683,23 +660,11 @@ public class TextToSpeech { mITts.addEarcon(mPackageName, earcon, packagename, resourceId); return SUCCESS; } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addEarcon", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addEarcon", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addEarcon", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addEarcon", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addEarcon", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addEarcon", e); } return ERROR; } @@ -730,23 +695,11 @@ public class TextToSpeech { mITts.addEarconFile(mPackageName, earcon, filename); return SUCCESS; } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addEarcon", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addEarcon", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addEarcon", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addEarcon", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - addEarcon", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("addEarcon", e); } return ERROR; } @@ -790,27 +743,15 @@ public class TextToSpeech { } result = mITts.speak(mPackageName, text, queueMode, mCachedParams); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - speak", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("speak", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - speak", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("speak", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - speak", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("speak", e); } finally { resetCachedParams(); - return result; } + return result; } } @@ -849,27 +790,15 @@ public class TextToSpeech { } result = mITts.playEarcon(mPackageName, earcon, queueMode, null); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - playEarcon", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("playEarcon", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - playEarcon", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("playEarcon", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - playEarcon", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("playEarcon", e); } finally { resetCachedParams(); - return result; } + return result; } } @@ -901,27 +830,15 @@ public class TextToSpeech { } result = mITts.playSilence(mPackageName, durationInMs, queueMode, mCachedParams); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - playSilence", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("playSilence", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - playSilence", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("playSilence", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - playSilence", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("playSilence", e); } finally { resetCachedParams(); - return result; } + return result; } } @@ -939,23 +856,11 @@ public class TextToSpeech { try { return mITts.isSpeaking(); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - isSpeaking", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("isSpeaking", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - isSpeaking", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("isSpeaking", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - isSpeaking", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("isSpeaking", e); } return false; } @@ -977,26 +882,13 @@ public class TextToSpeech { try { result = mITts.stop(mPackageName); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - stop", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("stop", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - stop", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("stop", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - stop", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return result; + restart("stop", e); } + return result; } } @@ -1032,20 +924,11 @@ public class TextToSpeech { } } } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setSpeechRate", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("setSpeechRate", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setSpeechRate", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return result; + restart("setSpeechRate", e); } + return result; } } @@ -1077,20 +960,11 @@ public class TextToSpeech { result = SUCCESS; } } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setPitch", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("setPitch", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setPitch", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return result; + restart("setPitch", e); } + return result; } } @@ -1141,26 +1015,13 @@ public class TextToSpeech { } } } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setLanguage", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("setLanguage", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setLanguage", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("setLanguage", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setLanguage", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return result; + restart("setLanguage", e); } + return result; } } @@ -1191,23 +1052,11 @@ public class TextToSpeech { mCachedParams[Engine.PARAM_POSITION_VARIANT + 1]); } } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - getLanguage", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("getLanguage", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - getLanguage", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("getLanguage", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - getLanguage", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("getLanguage", e); } return null; } @@ -1233,26 +1082,13 @@ public class TextToSpeech { result = mITts.isLanguageAvailable(loc.getISO3Language(), loc.getISO3Country(), loc.getVariant(), mCachedParams); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - isLanguageAvailable", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("isLanguageAvailable", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - isLanguageAvailable", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("isLanguageAvailable", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - isLanguageAvailable", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return result; + restart("isLanguageAvailable", e); } + return result; } } @@ -1293,27 +1129,15 @@ public class TextToSpeech { result = mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename) ? SUCCESS : ERROR; } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - synthesizeToFile", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("synthesizeToFile", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - synthesizeToFile", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("synthesizeToFile", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - synthesizeToFile", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("synthesizeToFile", e); } finally { resetCachedParams(); - return result; } + return result; } } @@ -1366,26 +1190,13 @@ public class TextToSpeech { try { result = mITts.registerCallback(mPackageName, mITtscallback); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - registerCallback", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("registerCallback", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - registerCallback", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("registerCallback", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - registerCallback", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return result; + restart("registerCallback", e); } + return result; } } @@ -1409,26 +1220,13 @@ public class TextToSpeech { mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = enginePackageName; } } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("setEngineByPackageName", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("setEngineByPackageName", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return result; + restart("setEngineByPackageName", e); } + return result; } } @@ -1447,26 +1245,13 @@ public class TextToSpeech { try { engineName = mITts.getDefaultEngine(); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("getDefaultEngine", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("getDefaultEngine", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return engineName; + restart("getDefaultEngine", e); } + return engineName; } } @@ -1486,26 +1271,23 @@ public class TextToSpeech { try { defaultsEnforced = mITts.areDefaultsEnforced(); } catch (RemoteException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - areDefaultsEnforced", "RemoteException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("areDefaultsEnforced", e); } catch (NullPointerException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - areDefaultsEnforced", "NullPointerException"); - e.printStackTrace(); - mStarted = false; - initTts(); + restart("areDefaultsEnforced", e); } catch (IllegalStateException e) { - // TTS died; restart it. - Log.e("TextToSpeech.java - areDefaultsEnforced", "IllegalStateException"); - e.printStackTrace(); - mStarted = false; - initTts(); - } finally { - return defaultsEnforced; + restart("areDefaultsEnforced", e); } + return defaultsEnforced; } } + + /** + * Restarts the TTS after a failure. + */ + private void restart(String method, Exception e) { + // TTS died; restart it. + Log.e(TAG, method, e); + mStarted = false; + initTts(); + } } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index a826a97..9e48eff 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -235,6 +235,8 @@ public class StaticLayout extends Layout { } else { MetricAffectingSpan[] spans = spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class); + spans = TextUtils.removeEmptySpans(spans, spanned, + MetricAffectingSpan.class); measured.addStyleRun(paint, spans, spanLen, fm); } } diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 90279d1..1b7f2f3 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -127,12 +127,12 @@ class TextLine { boolean hasReplacement = false; if (text instanceof Spanned) { mSpanned = (Spanned) text; - hasReplacement = mSpanned.getSpans(start, limit, - ReplacementSpan.class).length > 0; + ReplacementSpan[] spans = mSpanned.getSpans(start, limit, ReplacementSpan.class); + spans = TextUtils.removeEmptySpans(spans, mSpanned, ReplacementSpan.class); + hasReplacement = spans.length > 0; } - mCharsValid = hasReplacement || hasTabs || - directions != Layout.DIRS_ALL_LEFT_TO_RIGHT; + mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT; if (mCharsValid) { if (mChars == null || mChars.length < mLen) { @@ -147,10 +147,11 @@ class TextLine { // zero-width characters. char[] chars = mChars; for (int i = start, inext; i < limit; i = inext) { - inext = mSpanned.nextSpanTransition(i, limit, - ReplacementSpan.class); - if (mSpanned.getSpans(i, inext, ReplacementSpan.class) - .length > 0) { // transition into a span + inext = mSpanned.nextSpanTransition(i, limit, ReplacementSpan.class); + ReplacementSpan[] spans = mSpanned.getSpans(i, inext, ReplacementSpan.class); + spans = TextUtils.removeEmptySpans(spans, mSpanned, ReplacementSpan.class); + if (spans.length > 0) { + // transition into a span chars[i - start] = '\ufffc'; for (int j = i - start + 1, e = inext - start; j < e; ++j) { chars[j] = '\ufeff'; // used as ZWNBS, marks positions to skip @@ -197,7 +198,6 @@ class TextLine { boolean runIsRtl = (runs[i+1] & Layout.RUN_RTL_FLAG) != 0; int segstart = runStart; - char[] chars = mChars; for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) { int codept = 0; Bitmap bm = null; @@ -629,6 +629,7 @@ class TextLine { MetricAffectingSpan[] spans = mSpanned.getSpans(mStart + spanStart, mStart + spanLimit, MetricAffectingSpan.class); + spans = TextUtils.removeEmptySpans(spans, mSpanned, MetricAffectingSpan.class); if (spans.length > 0) { ReplacementSpan replacement = null; @@ -835,6 +836,7 @@ class TextLine { mlimit = inext < measureLimit ? inext : measureLimit; MetricAffectingSpan[] spans = mSpanned.getSpans(mStart + i, mStart + mlimit, MetricAffectingSpan.class); + spans = TextUtils.removeEmptySpans(spans, mSpanned, MetricAffectingSpan.class); if (spans.length > 0) { ReplacementSpan replacement = null; @@ -868,6 +870,7 @@ class TextLine { CharacterStyle[] spans = mSpanned.getSpans(mStart + j, mStart + jnext, CharacterStyle.class); + spans = TextUtils.removeEmptySpans(spans, mSpanned, CharacterStyle.class); wp.set(mPaint); for (int k = 0; k < spans.length; k++) { diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index d5010c6..ee6342a 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -44,6 +44,7 @@ import android.text.style.URLSpan; import android.text.style.UnderlineSpan; import android.util.Printer; +import java.lang.reflect.Array; import java.util.Iterator; import java.util.regex.Pattern; @@ -54,7 +55,7 @@ public class TextUtils { public static void getChars(CharSequence s, int start, int end, char[] dest, int destoff) { - Class c = s.getClass(); + Class<? extends CharSequence> c = s.getClass(); if (c == String.class) ((String) s).getChars(start, end, dest, destoff); @@ -75,7 +76,7 @@ public class TextUtils { } public static int indexOf(CharSequence s, char ch, int start) { - Class c = s.getClass(); + Class<? extends CharSequence> c = s.getClass(); if (c == String.class) return ((String) s).indexOf(ch, start); @@ -84,7 +85,7 @@ public class TextUtils { } public static int indexOf(CharSequence s, char ch, int start, int end) { - Class c = s.getClass(); + Class<? extends CharSequence> c = s.getClass(); if (s instanceof GetChars || c == StringBuffer.class || c == StringBuilder.class || c == String.class) { @@ -125,7 +126,7 @@ public class TextUtils { } public static int lastIndexOf(CharSequence s, char ch, int last) { - Class c = s.getClass(); + Class<? extends CharSequence> c = s.getClass(); if (c == String.class) return ((String) s).lastIndexOf(ch, last); @@ -142,7 +143,7 @@ public class TextUtils { int end = last + 1; - Class c = s.getClass(); + Class<? extends CharSequence> c = s.getClass(); if (s instanceof GetChars || c == StringBuffer.class || c == StringBuilder.class || c == String.class) { @@ -499,6 +500,7 @@ public class TextUtils { return new String(buf); } + @Override public String toString() { return subSequence(0, length()).toString(); } @@ -563,6 +565,8 @@ public class TextUtils { public static final int TEXT_APPEARANCE_SPAN = 17; /** @hide */ public static final int ANNOTATION = 18; + /** @hide */ + public static final int CORRECTION_SPAN = 19; /** * Flatten a CharSequence and whatever styles can be copied across processes @@ -621,7 +625,7 @@ public class TextUtils { * Read and return a new CharSequence, possibly with styles, * from the parcel. */ - public CharSequence createFromParcel(Parcel p) { + public CharSequence createFromParcel(Parcel p) { int kind = p.readInt(); if (kind == 1) @@ -760,7 +764,7 @@ public class TextUtils { if (where >= 0) tb.setSpan(sources[i], where, where + sources[i].length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } for (int i = 0; i < sources.length; i++) { @@ -1114,7 +1118,6 @@ public class TextUtils { int remaining = commaCount + 1; int ok = 0; - int okRemaining = remaining; String okFormat = ""; int w = 0; @@ -1146,7 +1149,6 @@ public class TextUtils { if (w + moreWid <= avail) { ok = i + 1; - okRemaining = remaining; okFormat = format; } } @@ -1179,6 +1181,7 @@ public class TextUtils { MetricAffectingSpan.class); MetricAffectingSpan[] spans = sp.getSpans( spanStart, spanEnd, MetricAffectingSpan.class); + spans = TextUtils.removeEmptySpans(spans, sp, MetricAffectingSpan.class); width += mt.addStyleRun(paint, spans, spanEnd - spanStart, null); } } @@ -1537,6 +1540,56 @@ public class TextUtils { return false; } + /** + * Removes empty spans from the <code>spans</code> array. + * + * When parsing a Spanned using {@link Spanned#nextSpanTransition(int, int, Class)}, empty spans + * will (correctly) create span transitions, and calling getSpans on a slice of text bounded by + * one of these transitions will (correctly) include the empty overlapping span. + * + * However, these empty spans should not be taken into account when layouting or rendering the + * string and this method provides a way to filter getSpans' results accordingly. + * + * @param spans A list of spans retrieved using {@link Spanned#getSpans(int, int, Class)} from + * the <code>spanned</code> + * @param spanned The Spanned from which spans were extracted + * @return A subset of spans where empty spans ({@link Spanned#getSpanStart(Object)} == + * {@link Spanned#getSpanEnd(Object)} have been removed. The initial order is preserved + * @hide + */ + @SuppressWarnings("unchecked") + public static <T> T[] removeEmptySpans(T[] spans, Spanned spanned, Class<T> klass) { + T[] copy = null; + int count = 0; + + for (int i = 0; i < spans.length; i++) { + final T span = spans[i]; + final int start = spanned.getSpanStart(span); + final int end = spanned.getSpanEnd(span); + + if (start == end) { + if (copy == null) { + copy = (T[]) Array.newInstance(klass, spans.length - 1); + System.arraycopy(spans, 0, copy, 0, i); + count = i; + } + } else { + if (copy != null) { + copy[count] = span; + count++; + } + } + } + + if (copy != null) { + T[] result = (T[]) Array.newInstance(klass, count); + System.arraycopy(copy, 0, result, 0, count); + return result; + } else { + return spans; + } + } + private static Object sLock = new Object(); private static char[] sTemp = null; } diff --git a/core/java/android/text/style/CorrectionSpan.aidl b/core/java/android/text/style/CorrectionSpan.aidl new file mode 100644 index 0000000..82e3d04 --- /dev/null +++ b/core/java/android/text/style/CorrectionSpan.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.text.style; + +parcelable CorrectionSpan; diff --git a/core/java/android/text/style/CorrectionSpan.java b/core/java/android/text/style/CorrectionSpan.java new file mode 100644 index 0000000..43fb85d --- /dev/null +++ b/core/java/android/text/style/CorrectionSpan.java @@ -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. + */ + +package android.text.style; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.ParcelableSpan; +import android.text.TextUtils; + +import java.util.Arrays; +import java.util.Locale; + +/** + * Sets correction candidates of words under this span. + */ +public class CorrectionSpan implements ParcelableSpan { + + /** + * Flag for indicating that the input is verbatim. TextView refers to this flag to determine + * how it displays a word with CorrectionSpan. + */ + public static final int FLAG_VERBATIM = 0x0001; + + private static final int SUGGESTIONS_MAX_SIZE = 5; + + /* + * TODO: Needs to check the validity and add a feature that TextView will change + * the current IME to the other IME which is specified in CorrectionSpan. + * An IME needs to set the span by specifying the target IME and Subtype of CorrectionSpan. + * And the current IME might want to specify any IME as the target IME including other IMEs. + */ + + private final int mFlags; + private final String[] mSuggestions; + private final String mLocaleString; + private final String mOriginalString; + /* + * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo + * and InputMethodSubtype. + */ + + /** + * @param context Context for the application + * @param suggestions Suggestions for the string under the span + * @param flags Additional flags indicating how this span is handled in TextView + */ + public CorrectionSpan(Context context, String[] suggestions, int flags) { + this(context, null, suggestions, flags, null); + } + + /** + * @param locale Locale of the suggestions + * @param suggestions Suggestions for the string under the span + * @param flags Additional flags indicating how this span is handled in TextView + */ + public CorrectionSpan(Locale locale, String[] suggestions, int flags) { + this(null, locale, suggestions, flags, null); + } + + /** + * @param context Context for the application + * @param locale locale Locale of the suggestions + * @param suggestions Suggestions for the string under the span + * @param flags Additional flags indicating how this span is handled in TextView + * @param originalString originalString for suggestions + */ + public CorrectionSpan(Context context, Locale locale, String[] suggestions, int flags, + String originalString) { + final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length); + mSuggestions = Arrays.copyOf(suggestions, N); + mFlags = flags; + if (context != null && locale == null) { + mLocaleString = context.getResources().getConfiguration().locale.toString(); + } else { + mLocaleString = locale.toString(); + } + mOriginalString = originalString; + } + + public CorrectionSpan(Parcel src) { + mSuggestions = src.readStringArray(); + mFlags = src.readInt(); + mLocaleString = src.readString(); + mOriginalString = src.readString(); + } + + /** + * @return suggestions + */ + public String[] getSuggestions() { + return Arrays.copyOf(mSuggestions, mSuggestions.length); + } + + /** + * @return locale of suggestions + */ + public String getLocale() { + return mLocaleString; + } + + /** + * @return original string of suggestions + */ + public String getOriginalString() { + return mOriginalString; + } + + public int getFlags() { + return mFlags; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeStringArray(mSuggestions); + dest.writeInt(mFlags); + dest.writeString(mLocaleString); + dest.writeString(mOriginalString); + } + + @Override + public int getSpanTypeId() { + return TextUtils.CORRECTION_SPAN; + } + + public static final Parcelable.Creator<CorrectionSpan> CREATOR = + new Parcelable.Creator<CorrectionSpan>() { + @Override + public CorrectionSpan createFromParcel(Parcel source) { + return new CorrectionSpan(source); + } + + @Override + public CorrectionSpan[] newArray(int size) { + return new CorrectionSpan[size]; + } + }; +} diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java index 8f44895..563c500 100644 --- a/core/java/android/util/JsonReader.java +++ b/core/java/android/util/JsonReader.java @@ -86,7 +86,11 @@ import java.util.List; * * public List<Message> readJsonStream(InputStream in) throws IOException { * JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); - * return readMessagesArray(reader); + * try { + * return readMessagesArray(reader); + * } finally { + * reader.close(); + * } * } * * public List<Message> readMessagesArray(JsonReader reader) throws IOException { diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java index 834dac3..5540000 100644 --- a/core/java/android/util/LruCache.java +++ b/core/java/android/util/LruCache.java @@ -304,7 +304,8 @@ public class LruCache<K, V> { } /** - * Returns the number of times {@link #get} returned a value. + * Returns the number of times {@link #get} returned a value that was + * already present in the cache. */ public synchronized final int hitCount() { return hitCount; diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 14f2e9d..b8c5c2a 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -39,6 +39,12 @@ import android.text.TextUtils; * An implementation of Canvas on top of OpenGL ES 2.0. */ class GLES20Canvas extends HardwareCanvas { + // Must match modifiers used in the JNI layer + private static final int MODIFIER_NONE = 0; + private static final int MODIFIER_SHADOW = 1; + private static final int MODIFIER_SHADER = 2; + private static final int MODIFIER_COLOR_FILTER = 4; + private final boolean mOpaque; private int mRenderer; @@ -259,10 +265,10 @@ class GLES20Canvas extends HardwareCanvas { void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) { final GLES20Layer glLayer = (GLES20Layer) layer; - boolean hasColorFilter = paint != null && setupColorFilter(paint); + int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE; final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint); - if (hasColorFilter) nResetModifiers(mRenderer); + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); } private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint); @@ -455,10 +461,10 @@ class GLES20Canvas extends HardwareCanvas { public int saveLayer(float left, float top, float right, float bottom, Paint paint, int saveFlags) { if (left < right && top < bottom) { - boolean hasColorFilter = paint != null && setupColorFilter(paint); + 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 (hasColorFilter) nResetModifiers(mRenderer); + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); return count; } return save(saveFlags); @@ -527,10 +533,10 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) { - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter, paint.mNativePaint); - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawArc(int renderer, float left, float top, @@ -545,11 +551,11 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) { // Shaders are ignored when drawing patches - boolean hasColorFilter = paint != null && setupColorFilter(paint); + 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 (hasColorFilter) nResetModifiers(mRenderer); + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); } private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks, @@ -558,10 +564,10 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { // Shaders are ignored when drawing bitmaps - boolean hasColorFilter = paint != null && setupColorFilter(paint); + 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 (hasColorFilter) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawBitmap( @@ -570,11 +576,11 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { // Shaders are ignored when drawing bitmaps - boolean hasColorFilter = paint != null && setupColorFilter(paint); + 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 (hasColorFilter) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff, @@ -583,7 +589,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { // Shaders are ignored when drawing bitmaps - boolean hasColorFilter = paint != null && setupColorFilter(paint); + int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; final int nativePaint = paint == null ? 0 : paint.mNativePaint; int left, top, right, bottom; @@ -600,17 +606,17 @@ class GLES20Canvas extends HardwareCanvas { nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint); - if (hasColorFilter) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } @Override public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { // Shaders are ignored when drawing bitmaps - boolean hasColorFilter = paint != null && setupColorFilter(paint); + int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right, src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint); - if (hasColorFilter) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer, @@ -621,13 +627,13 @@ class GLES20Canvas extends HardwareCanvas { public void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint) { // Shaders are ignored when drawing bitmaps - boolean hasColorFilter = paint != null && setupColorFilter(paint); + 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 (hasColorFilter) nResetModifiers(mRenderer); + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); } @Override @@ -655,11 +661,11 @@ class GLES20Canvas extends HardwareCanvas { colors = null; colorOffset = 0; - boolean hasColorFilter = paint != null && setupColorFilter(paint); + 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 (hasColorFilter) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer, @@ -668,9 +674,9 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawCircle(float cx, float cy, float radius, Paint paint) { - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint); - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawCircle(int renderer, float cx, float cy, @@ -702,9 +708,9 @@ class GLES20Canvas extends HardwareCanvas { if ((offset | count) < 0 || offset + count > pts.length) { throw new IllegalArgumentException("The lines array must contain 4 elements per line."); } - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint); - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawLines(int renderer, float[] points, @@ -717,9 +723,9 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawOval(RectF oval, Paint paint) { - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint); - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawOval(int renderer, float left, float top, @@ -734,7 +740,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawPath(Path path, Paint paint) { - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); if (path.isSimplePath) { if (path.rects != null) { nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint); @@ -742,7 +748,7 @@ class GLES20Canvas extends HardwareCanvas { } else { nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint); } - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawPath(int renderer, int path, int paint); @@ -767,19 +773,24 @@ class GLES20Canvas extends HardwareCanvas { public void drawPoint(float x, float y, Paint paint) { mPoint[0] = x; mPoint[1] = y; - drawPoints(mPoint, 0, 1, paint); + drawPoints(mPoint, 0, 2, paint); } @Override - public void drawPoints(float[] pts, int offset, int count, Paint paint) { - // TODO: Implement + public void drawPoints(float[] pts, Paint paint) { + drawPoints(pts, 0, pts.length, paint); } @Override - public void drawPoints(float[] pts, Paint paint) { - drawPoints(pts, 0, pts.length / 2, paint); + 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); } + private static native void nDrawPoints(int renderer, float[] points, + int offset, int count, int paint); + @Override public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { // TODO: Implement @@ -792,9 +803,9 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawRect(float left, float top, float right, float bottom, Paint paint) { - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawRect(int renderer, float left, float top, @@ -817,10 +828,10 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint.mNativePaint); - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawRoundRect(int renderer, float left, float top, @@ -832,11 +843,11 @@ class GLES20Canvas extends HardwareCanvas { throw new IndexOutOfBoundsException(); } - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); try { nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint); } finally { - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } } @@ -845,7 +856,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); try { if (text instanceof String || text instanceof SpannedString || text instanceof SpannableString) { @@ -862,7 +873,7 @@ class GLES20Canvas extends HardwareCanvas { TemporaryBuffer.recycle(buf); } } finally { - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } } @@ -872,11 +883,11 @@ class GLES20Canvas extends HardwareCanvas { throw new IndexOutOfBoundsException(); } - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); try { nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint); } finally { - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } } @@ -885,12 +896,12 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawText(String text, float x, float y, Paint paint) { - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); try { nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags, paint.mNativePaint); } finally { - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } } @@ -915,12 +926,12 @@ class GLES20Canvas extends HardwareCanvas { throw new IllegalArgumentException("Unknown direction: " + dir); } - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); try { nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir, paint.mNativePaint); } finally { - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } } @@ -934,7 +945,7 @@ class GLES20Canvas extends HardwareCanvas { throw new IndexOutOfBoundsException(); } - boolean hasModifier = setupModifiers(paint); + int modifiers = setupModifiers(paint); try { int flags = dir == 0 ? 0 : 1; if (text instanceof String || text instanceof SpannedString || @@ -954,7 +965,7 @@ class GLES20Canvas extends HardwareCanvas { TemporaryBuffer.recycle(buf); } } finally { - if (hasModifier) nResetModifiers(mRenderer); + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } } @@ -968,43 +979,57 @@ class GLES20Canvas extends HardwareCanvas { // TODO: Implement } - private boolean setupModifiers(Paint paint) { - boolean hasModifier = false; + private int setupModifiers(Bitmap b, Paint paint) { + if (b.getConfig() == Bitmap.Config.ALPHA_8) { + return setupModifiers(paint); + } + + final ColorFilter filter = paint.getColorFilter(); + if (filter != null) { + nSetupColorFilter(mRenderer, filter.nativeColorFilter); + return MODIFIER_COLOR_FILTER; + } + + return MODIFIER_NONE; + } + + private int setupModifiers(Paint paint) { + int modifiers = MODIFIER_NONE; if (paint.hasShadow) { nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy, paint.shadowColor); - hasModifier = true; + modifiers |= MODIFIER_SHADOW; } final Shader shader = paint.getShader(); if (shader != null) { nSetupShader(mRenderer, shader.native_shader); - hasModifier = true; + modifiers |= MODIFIER_SHADER; } final ColorFilter filter = paint.getColorFilter(); if (filter != null) { nSetupColorFilter(mRenderer, filter.nativeColorFilter); - hasModifier = true; + modifiers |= MODIFIER_COLOR_FILTER; } - return hasModifier; + return modifiers; } - private boolean setupColorFilter(Paint paint) { + private int setupColorFilter(Paint paint) { final ColorFilter filter = paint.getColorFilter(); if (filter != null) { nSetupColorFilter(mRenderer, filter.nativeColorFilter); - return true; + return MODIFIER_COLOR_FILTER; } - return false; + return MODIFIER_NONE; } - + private static native void nSetupShader(int renderer, int shader); private static native void nSetupColorFilter(int renderer, int colorFilter); private static native void nSetupShadow(int renderer, float radius, float dx, float dy, int color); - private static native void nResetModifiers(int renderer); + private static native void nResetModifiers(int renderer, int modifiers); } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 8584bf2..28541fe 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -20,7 +20,7 @@ package android.view; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; -import android.os.SystemClock; +import android.os.*; import android.util.EventLog; import android.util.Log; @@ -256,6 +256,7 @@ public abstract class HardwareRenderer { @SuppressWarnings({"deprecation"}) static abstract class GlRenderer extends HardwareRenderer { + // These values are not exposed in our EGL APIs private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; private static final int EGL_SURFACE_TYPE = 0x3033; private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; @@ -290,7 +291,7 @@ public abstract class HardwareRenderer { GlRenderer(int glVersion, boolean translucent) { mGlVersion = glVersion; mTranslucent = translucent; - final String dirtyProperty = System.getProperty(RENDER_DIRTY_REGIONS_PROPERTY, "true"); + final String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true"); //noinspection PointlessBooleanExpression,ConstantConditions mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty); } diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 81d5a6e..8070c6a 100755 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -566,6 +566,19 @@ public class KeyEvent extends InputEvent implements Parcelable { public static final int KEYCODE_BUTTON_15 = 202; /** Key code constant: Generic Game Pad Button #16.*/ public static final int KEYCODE_BUTTON_16 = 203; + /** Key code constant: Language Switch key. + * Toggles the current input language such as switching between English and Japanese on + * a QWERTY keyboard. On some devices, the same function may be performed by + * pressing Shift+Spacebar. */ + public static final int KEYCODE_LANGUAGE_SWITCH = 204; + /** Key code constant: Manner Mode key. + * Toggles silent or vibrate mode on and off to make the device behave more politely + * in certain settings such as on a crowded train. On some devices, the key may only + * operate when long-pressed. */ + public static final int KEYCODE_MANNER_MODE = 205; + /** Key code constant: 3D Mode key. + * Toggles the display between 2D and 3D mode. */ + public static final int KEYCODE_3D_MODE = 206; private static final int LAST_KEYCODE = KEYCODE_BUTTON_16; @@ -791,6 +804,9 @@ public class KeyEvent extends InputEvent implements Parcelable { names.append(KEYCODE_BUTTON_14, "KEYCODE_BUTTON_14"); names.append(KEYCODE_BUTTON_15, "KEYCODE_BUTTON_15"); names.append(KEYCODE_BUTTON_16, "KEYCODE_BUTTON_16"); + names.append(KEYCODE_LANGUAGE_SWITCH, "KEYCODE_LANGUAGE_SWITCH"); + names.append(KEYCODE_MANNER_MODE, "KEYCODE_MANNER_MODE"); + names.append(KEYCODE_3D_MODE, "KEYCODE_3D_MODE"); }; // Symbolic names of all metakeys in bit order from least significant to most significant. diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index a17db5d..3c34479 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -172,6 +172,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { * recent point, as well as any intermediate points since the last * hover move event. * <p> + * This action is always delivered to the window or view under the pointer. + * </p><p> * This action is not a touch event so it is delivered to * {@link View#onGenericMotionEvent(MotionEvent)} rather than * {@link View#onTouchEvent(MotionEvent)}. @@ -184,8 +186,9 @@ public final class MotionEvent extends InputEvent implements Parcelable { * vertical and/or horizontal scroll offsets. Use {@link #getAxisValue(int)} * to retrieve the information from {@link #AXIS_VSCROLL} and {@link #AXIS_HSCROLL}. * The pointer may or may not be down when this event is dispatched. - * This action is always delivered to the winder under the pointer, which - * may not be the window currently touched. + * <p></p> + * This action is always delivered to the window or view under the pointer, which + * may not be the window or view currently touched. * <p> * This action is not a touch event so it is delivered to * {@link View#onGenericMotionEvent(MotionEvent)} rather than @@ -195,6 +198,32 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int ACTION_SCROLL = 8; /** + * Constant for {@link #getAction}: The pointer is not down but has entered the + * boundaries of a window or view. + * <p> + * This action is always delivered to the window or view under the pointer. + * </p><p> + * This action is not a touch event so it is delivered to + * {@link View#onGenericMotionEvent(MotionEvent)} rather than + * {@link View#onTouchEvent(MotionEvent)}. + * </p> + */ + public static final int ACTION_HOVER_ENTER = 9; + + /** + * Constant for {@link #getAction}: The pointer is not down but has exited the + * boundaries of a window or view. + * <p> + * This action is always delivered to the window or view that was previously under the pointer. + * </p><p> + * This action is not a touch event so it is delivered to + * {@link View#onGenericMotionEvent(MotionEvent)} rather than + * {@link View#onTouchEvent(MotionEvent)}. + * </p> + */ + public static final int ACTION_HOVER_EXIT = 10; + + /** * Bits in the action code that represent a pointer index, used with * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Shifting * down by {@link #ACTION_POINTER_INDEX_SHIFT} provides the actual pointer @@ -1354,9 +1383,9 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Returns true if this motion event is a touch event. * <p> - * Specifically excludes pointer events with action {@link #ACTION_HOVER_MOVE} - * or {@link #ACTION_SCROLL} because they are not actually touch events - * (the pointer is not down). + * Specifically excludes pointer events with action {@link #ACTION_HOVER_MOVE}, + * {@link #ACTION_HOVER_ENTER}, {@link #ACTION_HOVER_EXIT}, or {@link #ACTION_SCROLL} + * because they are not actually touch events (the pointer is not down). * </p> * @return True if this motion event is a touch event. * @hide @@ -2313,6 +2342,10 @@ public final class MotionEvent extends InputEvent implements Parcelable { return "ACTION_HOVER_MOVE"; case ACTION_SCROLL: return "ACTION_SCROLL"; + case ACTION_HOVER_ENTER: + return "ACTION_HOVER_ENTER"; + case ACTION_HOVER_EXIT: + return "ACTION_HOVER_EXIT"; } int index = (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT; switch (action & ACTION_MASK) { diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java index 4ab2881..fccef2b 100644 --- a/core/java/android/view/VelocityTracker.java +++ b/core/java/android/view/VelocityTracker.java @@ -16,8 +16,6 @@ package android.view; -import android.util.Config; -import android.util.Log; import android.util.Poolable; import android.util.Pool; import android.util.Pools; @@ -25,24 +23,15 @@ import android.util.PoolableManager; /** * Helper for tracking the velocity of touch events, for implementing - * flinging and other such gestures. Use {@link #obtain} to retrieve a - * new instance of the class when you are going to begin tracking, put - * the motion events you receive into it with {@link #addMovement(MotionEvent)}, - * and when you want to determine the velocity call - * {@link #computeCurrentVelocity(int)} and then {@link #getXVelocity()} - * and {@link #getXVelocity()}. + * flinging and other such gestures. + * + * Use {@link #obtain} to retrieve a new instance of the class when you are going + * to begin tracking. Put the motion events you receive into it with + * {@link #addMovement(MotionEvent)}. When you want to determine the velocity call + * {@link #computeCurrentVelocity(int)} and then call {@link #getXVelocity(int)} + * and {@link #getXVelocity(int)} to retrieve the velocity for each pointer id. */ public final class VelocityTracker implements Poolable<VelocityTracker> { - private static final String TAG = "VelocityTracker"; - private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG || Config.LOGV; - - private static final int NUM_PAST = 10; - private static final int MAX_AGE_MILLISECONDS = 200; - - private static final int POINTER_POOL_CAPACITY = 20; - private static final int INVALID_POINTER = -1; - private static final Pool<VelocityTracker> sPool = Pools.synchronizedPool( Pools.finitePool(new PoolableManager<VelocityTracker>() { public VelocityTracker newInstance() { @@ -56,31 +45,20 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { element.clear(); } }, 2)); - - private static Pointer sRecycledPointerListHead; - private static int sRecycledPointerCount; - - private static final class Pointer { - public Pointer next; - - public int id; - public float xVelocity; - public float yVelocity; - - public final float[] pastX = new float[NUM_PAST]; - public final float[] pastY = new float[NUM_PAST]; - public final long[] pastTime = new long[NUM_PAST]; // uses Long.MIN_VALUE as a sentinel - - public int generation; - } - - private Pointer mPointerListHead; // sorted by id in increasing order - private int mLastTouchIndex; - private int mGeneration; - private int mActivePointerId; + private static final int ACTIVE_POINTER_ID = -1; + + private int mPtr; private VelocityTracker mNext; + private static native int nativeInitialize(); + private static native void nativeDispose(int ptr); + private static native void nativeClear(int ptr); + private static native void nativeAddMovement(int ptr, MotionEvent event); + private static native void nativeComputeCurrentVelocity(int ptr, int units, float maxVelocity); + private static native float nativeGetXVelocity(int ptr, int id); + private static native float nativeGetYVelocity(int ptr, int id); + /** * Retrieve a new VelocityTracker object to watch the velocity of a * motion. Be sure to call {@link #recycle} when done. You should @@ -116,18 +94,26 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { } private VelocityTracker() { - clear(); + mPtr = nativeInitialize(); } - + + @Override + protected void finalize() throws Throwable { + try { + if (mPtr != 0) { + nativeDispose(mPtr); + mPtr = 0; + } + } finally { + super.finalize(); + } + } + /** * Reset the velocity tracker back to its initial state. */ public void clear() { - releasePointerList(mPointerListHead); - - mPointerListHead = null; - mLastTouchIndex = 0; - mActivePointerId = INVALID_POINTER; + nativeClear(mPtr); } /** @@ -137,110 +123,13 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * final {@link MotionEvent#ACTION_UP}. You can, however, call this * for whichever events you desire. * - * @param ev The MotionEvent you received and would like to track. + * @param event The MotionEvent you received and would like to track. */ - public void addMovement(MotionEvent ev) { - final int historySize = ev.getHistorySize(); - final int pointerCount = ev.getPointerCount(); - final int lastTouchIndex = mLastTouchIndex; - final int nextTouchIndex = (lastTouchIndex + 1) % NUM_PAST; - final int finalTouchIndex = (nextTouchIndex + historySize) % NUM_PAST; - final int generation = mGeneration++; - - mLastTouchIndex = finalTouchIndex; - - // Update pointer data. - Pointer previousPointer = null; - for (int i = 0; i < pointerCount; i++){ - final int pointerId = ev.getPointerId(i); - - // Find the pointer data for this pointer id. - // This loop is optimized for the common case where pointer ids in the event - // are in sorted order. However, we check for this case explicitly and - // perform a full linear scan from the start if needed. - Pointer nextPointer; - if (previousPointer == null || pointerId < previousPointer.id) { - previousPointer = null; - nextPointer = mPointerListHead; - } else { - nextPointer = previousPointer.next; - } - - final Pointer pointer; - for (;;) { - if (nextPointer != null) { - final int nextPointerId = nextPointer.id; - if (nextPointerId == pointerId) { - pointer = nextPointer; - break; - } - if (nextPointerId < pointerId) { - nextPointer = nextPointer.next; - continue; - } - } - - // Pointer went down. Add it to the list. - // Write a sentinel at the end of the pastTime trace so we will be able to - // tell when the trace started. - if (mActivePointerId == INVALID_POINTER) { - // Congratulations! You're the new active pointer! - mActivePointerId = pointerId; - } - pointer = obtainPointer(); - pointer.id = pointerId; - pointer.pastTime[lastTouchIndex] = Long.MIN_VALUE; - pointer.next = nextPointer; - if (previousPointer == null) { - mPointerListHead = pointer; - } else { - previousPointer.next = pointer; - } - break; - } - - pointer.generation = generation; - previousPointer = pointer; - - final float[] pastX = pointer.pastX; - final float[] pastY = pointer.pastY; - final long[] pastTime = pointer.pastTime; - - for (int j = 0; j < historySize; j++) { - final int touchIndex = (nextTouchIndex + j) % NUM_PAST; - pastX[touchIndex] = ev.getHistoricalX(i, j); - pastY[touchIndex] = ev.getHistoricalY(i, j); - pastTime[touchIndex] = ev.getHistoricalEventTime(j); - } - pastX[finalTouchIndex] = ev.getX(i); - pastY[finalTouchIndex] = ev.getY(i); - pastTime[finalTouchIndex] = ev.getEventTime(); - } - - // Find removed pointers. - previousPointer = null; - for (Pointer pointer = mPointerListHead; pointer != null; ) { - final Pointer nextPointer = pointer.next; - final int pointerId = pointer.id; - if (pointer.generation != generation) { - // Pointer went up. Remove it from the list. - if (previousPointer == null) { - mPointerListHead = nextPointer; - } else { - previousPointer.next = nextPointer; - } - releasePointer(pointer); - - if (pointerId == mActivePointerId) { - // Pick a new active pointer. How is arbitrary. - mActivePointerId = mPointerListHead != null ? - mPointerListHead.id : INVALID_POINTER; - } - } else { - previousPointer = pointer; - } - pointer = nextPointer; + public void addMovement(MotionEvent event) { + if (event == null) { + throw new IllegalArgumentException("event must not be null"); } + nativeAddMovement(mPtr, event); } /** @@ -250,7 +139,7 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * @see #computeCurrentVelocity(int, float) */ public void computeCurrentVelocity(int units) { - computeCurrentVelocity(units, Float.MAX_VALUE); + nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE); } /** @@ -267,78 +156,7 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * must be positive. */ public void computeCurrentVelocity(int units, float maxVelocity) { - final int lastTouchIndex = mLastTouchIndex; - - for (Pointer pointer = mPointerListHead; pointer != null; pointer = pointer.next) { - final long[] pastTime = pointer.pastTime; - - // Search backwards in time for oldest acceptable time. - // Stop at the beginning of the trace as indicated by the sentinel time Long.MIN_VALUE. - int oldestTouchIndex = lastTouchIndex; - int numTouches = 1; - final long minTime = pastTime[lastTouchIndex] - MAX_AGE_MILLISECONDS; - while (numTouches < NUM_PAST) { - final int nextOldestTouchIndex = (oldestTouchIndex + NUM_PAST - 1) % NUM_PAST; - final long nextOldestTime = pastTime[nextOldestTouchIndex]; - if (nextOldestTime < minTime) { // also handles end of trace sentinel - break; - } - oldestTouchIndex = nextOldestTouchIndex; - numTouches += 1; - } - - // If we have a lot of samples, skip the last received sample since it is - // probably pretty noisy compared to the sum of all of the traces already acquired. - if (numTouches > 3) { - numTouches -= 1; - } - - // Kind-of stupid. - final float[] pastX = pointer.pastX; - final float[] pastY = pointer.pastY; - - final float oldestX = pastX[oldestTouchIndex]; - final float oldestY = pastY[oldestTouchIndex]; - final long oldestTime = pastTime[oldestTouchIndex]; - - float accumX = 0; - float accumY = 0; - - for (int i = 1; i < numTouches; i++) { - final int touchIndex = (oldestTouchIndex + i) % NUM_PAST; - final int duration = (int)(pastTime[touchIndex] - oldestTime); - - if (duration == 0) continue; - - float delta = pastX[touchIndex] - oldestX; - float velocity = (delta / duration) * units; // pixels/frame. - accumX = (accumX == 0) ? velocity : (accumX + velocity) * .5f; - - delta = pastY[touchIndex] - oldestY; - velocity = (delta / duration) * units; // pixels/frame. - accumY = (accumY == 0) ? velocity : (accumY + velocity) * .5f; - } - - if (accumX < -maxVelocity) { - accumX = - maxVelocity; - } else if (accumX > maxVelocity) { - accumX = maxVelocity; - } - - if (accumY < -maxVelocity) { - accumY = - maxVelocity; - } else if (accumY > maxVelocity) { - accumY = maxVelocity; - } - - pointer.xVelocity = accumX; - pointer.yVelocity = accumY; - - if (localLOGV) { - Log.v(TAG, "Pointer " + pointer.id - + ": Y velocity=" + accumX +" X velocity=" + accumY + " N=" + numTouches); - } - } + nativeComputeCurrentVelocity(mPtr, units, maxVelocity); } /** @@ -348,8 +166,7 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * @return The previously computed X velocity. */ public float getXVelocity() { - Pointer pointer = getPointer(mActivePointerId); - return pointer != null ? pointer.xVelocity : 0; + return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID); } /** @@ -359,8 +176,7 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * @return The previously computed Y velocity. */ public float getYVelocity() { - Pointer pointer = getPointer(mActivePointerId); - return pointer != null ? pointer.yVelocity : 0; + return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID); } /** @@ -371,8 +187,7 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * @return The previously computed X velocity. */ public float getXVelocity(int id) { - Pointer pointer = getPointer(id); - return pointer != null ? pointer.xVelocity : 0; + return nativeGetXVelocity(mPtr, id); } /** @@ -383,68 +198,6 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * @return The previously computed Y velocity. */ public float getYVelocity(int id) { - Pointer pointer = getPointer(id); - return pointer != null ? pointer.yVelocity : 0; - } - - private Pointer getPointer(int id) { - for (Pointer pointer = mPointerListHead; pointer != null; pointer = pointer.next) { - if (pointer.id == id) { - return pointer; - } - } - return null; - } - - private static Pointer obtainPointer() { - synchronized (sPool) { - if (sRecycledPointerCount != 0) { - Pointer element = sRecycledPointerListHead; - sRecycledPointerCount -= 1; - sRecycledPointerListHead = element.next; - element.next = null; - return element; - } - } - return new Pointer(); - } - - private static void releasePointer(Pointer pointer) { - synchronized (sPool) { - if (sRecycledPointerCount < POINTER_POOL_CAPACITY) { - pointer.next = sRecycledPointerListHead; - sRecycledPointerCount += 1; - sRecycledPointerListHead = pointer; - } - } - } - - private static void releasePointerList(Pointer pointer) { - if (pointer != null) { - synchronized (sPool) { - int count = sRecycledPointerCount; - if (count >= POINTER_POOL_CAPACITY) { - return; - } - - Pointer tail = pointer; - for (;;) { - count += 1; - if (count >= POINTER_POOL_CAPACITY) { - break; - } - - Pointer next = tail.next; - if (next == null) { - break; - } - tail = next; - } - - tail.next = sRecycledPointerListHead; - sRecycledPointerCount = count; - sRecycledPointerListHead = pointer; - } - } + return nativeGetYVelocity(mPtr, id); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 5a96efd..96cddfa 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1304,6 +1304,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility static final int VIEW_STATE_PRESSED = 1 << 4; static final int VIEW_STATE_ACTIVATED = 1 << 5; static final int VIEW_STATE_ACCELERATED = 1 << 6; + static final int VIEW_STATE_HOVERED = 1 << 7; static final int[] VIEW_STATE_IDS = new int[] { R.attr.state_window_focused, VIEW_STATE_WINDOW_FOCUSED, @@ -1313,6 +1314,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility R.attr.state_pressed, VIEW_STATE_PRESSED, R.attr.state_activated, VIEW_STATE_ACTIVATED, R.attr.state_accelerated, VIEW_STATE_ACCELERATED, + R.attr.state_hovered, VIEW_STATE_HOVERED, }; static { @@ -1623,6 +1625,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; /** + * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. + * @hide + */ + private static final int HOVERED = 0x10000000; + + /** * Indicates that pivotX or pivotY were explicitly set and we should not assume the center * for transform operations * @@ -4643,23 +4651,81 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * <p> * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} * are delivered to the view under the pointer. All other generic motion events are - * delivered to the focused view. + * delivered to the focused view. Hover events are handled specially and are delivered + * to {@link #onHoverEvent}. * </p> * * @param event The motion event to be dispatched. * @return True if the event was handled by the view, false otherwise. */ public boolean dispatchGenericMotionEvent(MotionEvent event) { + final int source = event.getSource(); + if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { + final int action = event.getAction(); + if (action == MotionEvent.ACTION_HOVER_ENTER + || action == MotionEvent.ACTION_HOVER_MOVE + || action == MotionEvent.ACTION_HOVER_EXIT) { + if (dispatchHoverEvent(event)) { + return true; + } + } else if (dispatchGenericPointerEvent(event)) { + return true; + } + } else if (dispatchGenericFocusedEvent(event)) { + return true; + } + //noinspection SimplifiableIfStatement if (mOnGenericMotionListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnGenericMotionListener.onGenericMotion(this, event)) { return true; } - return onGenericMotionEvent(event); } /** + * Dispatch a hover event. + * <p> + * Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead. + * </p> + * + * @param event The motion event to be dispatched. + * @return True if the event was handled by the view, false otherwise. + * @hide + */ + protected boolean dispatchHoverEvent(MotionEvent event) { + return onHoverEvent(event); + } + + /** + * Dispatch a generic motion event to the view under the first pointer. + * <p> + * Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead. + * </p> + * + * @param event The motion event to be dispatched. + * @return True if the event was handled by the view, false otherwise. + * @hide + */ + protected boolean dispatchGenericPointerEvent(MotionEvent event) { + return false; + } + + /** + * Dispatch a generic motion event to the currently focused view. + * <p> + * Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead. + * </p> + * + * @param event The motion event to be dispatched. + * @return True if the event was handled by the view, false otherwise. + * @hide + */ + protected boolean dispatchGenericFocusedEvent(MotionEvent event) { + return false; + } + + /** * Dispatch a pointer event. * <p> * Dispatches touch related pointer events to {@link #onTouchEvent} and all @@ -5223,15 +5289,92 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * </code> * * @param event The generic motion event being processed. - * - * @return Return true if you have consumed the event, false if you haven't. - * The default implementation always returns false. + * @return True if the event was handled, false otherwise. */ public boolean onGenericMotionEvent(MotionEvent event) { return false; } /** + * Implement this method to handle hover events. + * <p> + * Hover events are pointer events with action {@link MotionEvent#ACTION_HOVER_ENTER}, + * {@link MotionEvent#ACTION_HOVER_MOVE}, or {@link MotionEvent#ACTION_HOVER_EXIT}. + * </p><p> + * The view receives hover enter as the pointer enters the bounds of the view and hover + * exit as the pointer exits the bound of the view or just before the pointer goes down + * (which implies that {@link #onTouchEvent} will be called soon). + * </p><p> + * If the view would like to handle the hover event itself and prevent its children + * from receiving hover, it should return true from this method. If this method returns + * true and a child has already received a hover enter event, the child will + * automatically receive a hover exit event. + * </p><p> + * The default implementation sets the hovered state of the view if the view is + * clickable. + * </p> + * + * @param event The motion event that describes the hover. + * @return True if this view handled the hover event and does not want its children + * to receive the hover event. + */ + public boolean onHoverEvent(MotionEvent event) { + final int viewFlags = mViewFlags; + + if (((viewFlags & CLICKABLE) != CLICKABLE && + (viewFlags & LONG_CLICKABLE) != LONG_CLICKABLE)) { + // Nothing to do if the view is not clickable. + return false; + } + + if ((viewFlags & ENABLED_MASK) == DISABLED) { + // A disabled view that is clickable still consumes the hover events, it just doesn't + // respond to them. + return true; + } + + switch (event.getAction()) { + case MotionEvent.ACTION_HOVER_ENTER: + setHovered(true); + break; + + case MotionEvent.ACTION_HOVER_EXIT: + setHovered(false); + break; + } + + return true; + } + + /** + * Returns true if the view is currently hovered. + * + * @return True if the view is currently hovered. + */ + public boolean isHovered() { + return (mPrivateFlags & HOVERED) != 0; + } + + /** + * Sets whether the view is currently hovered. + * + * @param hovered True if the view is hovered. + */ + public void setHovered(boolean hovered) { + if (hovered) { + if ((mPrivateFlags & HOVERED) == 0) { + mPrivateFlags |= HOVERED; + refreshDrawableState(); + } + } else { + if ((mPrivateFlags & HOVERED) != 0) { + mPrivateFlags &= ~HOVERED; + refreshDrawableState(); + } + } + } + + /** * Implement this method to handle touch screen motion events. * * @param event The motion event. @@ -5241,6 +5384,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility final int viewFlags = mViewFlags; if ((viewFlags & ENABLED_MASK) == DISABLED) { + if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PRESSED) != 0) { + mPrivateFlags &= ~PRESSED; + refreshDrawableState(); + } // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. return (((viewFlags & CLICKABLE) == CLICKABLE || @@ -7212,8 +7359,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mPrivateFlags &= ~DRAWN; mPrivateFlags |= INVALIDATED; mPrivateFlags &= ~DRAWING_CACHE_VALID; - if (mParent != null && mAttachInfo != null && mAttachInfo.mHardwareAccelerated) { - mParent.invalidateChild(this, null); + if (mParent != null && mAttachInfo != null) { + if (mAttachInfo.mHardwareAccelerated) { + mParent.invalidateChild(this, null); + } else { + final Rect r = mAttachInfo.mTmpInvalRect; + r.set(0, 0, mRight - mLeft, mBottom - mTop); + // Don't call invalidate -- we don't want to internally scroll + // our own bounds + mParent.invalidateChild(this, r); + } } } } @@ -7319,8 +7474,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility */ public boolean post(Runnable action) { Handler handler; - if (mAttachInfo != null) { - handler = mAttachInfo.mHandler; + AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { + handler = attachInfo.mHandler; } else { // Assume that post will succeed later ViewRoot.getRunQueue().post(action); @@ -7348,8 +7504,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility */ public boolean postDelayed(Runnable action, long delayMillis) { Handler handler; - if (mAttachInfo != null) { - handler = mAttachInfo.mHandler; + AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { + handler = attachInfo.mHandler; } else { // Assume that post will succeed later ViewRoot.getRunQueue().postDelayed(action, delayMillis); @@ -7371,8 +7528,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility */ public boolean removeCallbacks(Runnable action) { Handler handler; - if (mAttachInfo != null) { - handler = mAttachInfo.mHandler; + AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { + handler = attachInfo.mHandler; } else { // Assume that post will succeed later ViewRoot.getRunQueue().removeCallbacks(action); @@ -7419,11 +7577,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility 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 - if (mAttachInfo != null) { + AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { Message msg = Message.obtain(); msg.what = AttachInfo.INVALIDATE_MSG; msg.obj = this; - mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); + attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); } } @@ -7443,7 +7602,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility // We try only with the AttachInfo because there's no point in invalidating // if we are not attached to our window - if (mAttachInfo != null) { + AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire(); info.target = this; info.left = left; @@ -7454,7 +7614,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility final Message msg = Message.obtain(); msg.what = AttachInfo.INVALIDATE_RECT_MSG; msg.obj = info; - mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); + attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); } } @@ -9873,6 +10033,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility // windows to better match their app. viewStateIndex |= VIEW_STATE_ACCELERATED; } + if ((privateFlags & HOVERED) != 0) viewStateIndex |= VIEW_STATE_HOVERED; drawableState = VIEW_STATE_SETS[viewStateIndex]; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 8dc86ac..058b826 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -147,6 +147,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @ViewDebug.ExportedProperty(category = "events") private float mLastTouchDownY; + // Child which last received ACTION_HOVER_ENTER and ACTION_HOVER_MOVE. + private View mHoveredChild; + /** * Internal flags. * @@ -1140,13 +1143,50 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return false; } - /** - * {@inheritDoc} - */ + /** @hide */ @Override - public boolean dispatchGenericMotionEvent(MotionEvent event) { - if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { - // Send the event to the child under the pointer. + protected boolean dispatchHoverEvent(MotionEvent event) { + // Send the hover enter or hover move event to the view group first. + // If it handles the event then a hovered child should receive hover exit. + boolean handled = false; + final boolean interceptHover; + final int action = event.getAction(); + if (action == MotionEvent.ACTION_HOVER_EXIT) { + interceptHover = true; + } else { + handled = super.dispatchHoverEvent(event); + interceptHover = handled; + } + + // Send successive hover events to the hovered child as long as the pointer + // remains within the child's bounds. + MotionEvent eventNoHistory = event; + if (mHoveredChild != null) { + final float x = event.getX(); + final float y = event.getY(); + + if (interceptHover + || !isTransformedTouchPointInView(x, y, mHoveredChild, null)) { + // Pointer exited the child. + // Send it a hover exit with only the most recent coordinates. We could + // try to find the exact point in history when the pointer left the view + // but it is not worth the effort. + eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory); + eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); + handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, mHoveredChild); + eventNoHistory.setAction(action); + + mHoveredChild = null; + } else if (action == MotionEvent.ACTION_HOVER_MOVE) { + // Pointer is still within the child. + handled |= dispatchTransformedGenericPointerEvent(event, mHoveredChild); + } + } + + // Find a new hovered child if needed. + if (!interceptHover && mHoveredChild == null + && (action == MotionEvent.ACTION_HOVER_ENTER + || action == MotionEvent.ACTION_HOVER_MOVE)) { final int childrenCount = mChildrenCount; if (childrenCount != 0) { final View[] children = mChildren; @@ -1155,45 +1195,88 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager for (int i = childrenCount - 1; i >= 0; i--) { final View child = children[i]; - if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE - && child.getAnimation() == null) { - // Skip invisible child unless it is animating. + if (!canViewReceivePointerEvents(child) + || !isTransformedTouchPointInView(x, y, child, null)) { continue; } - if (!isTransformedTouchPointInView(x, y, child, null)) { - // Scroll point is out of child's bounds. - continue; + // Found the hovered child. + mHoveredChild = child; + if (action == MotionEvent.ACTION_HOVER_MOVE) { + // Pointer was moving within the view group and entered the child. + // Send it a hover enter and hover move with only the most recent + // coordinates. We could try to find the exact point in history when + // the pointer entered the view but it is not worth the effort. + eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory); + eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); + handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, child); + eventNoHistory.setAction(action); + + handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, child); + } else { /* must be ACTION_HOVER_ENTER */ + // Pointer entered the child. + handled |= dispatchTransformedGenericPointerEvent(event, child); } + break; + } + } + } - final float offsetX = mScrollX - child.mLeft; - final float offsetY = mScrollY - child.mTop; - final boolean handled; - if (!child.hasIdentityMatrix()) { - MotionEvent transformedEvent = MotionEvent.obtain(event); - transformedEvent.offsetLocation(offsetX, offsetY); - transformedEvent.transform(child.getInverseMatrix()); - handled = child.dispatchGenericMotionEvent(transformedEvent); - transformedEvent.recycle(); - } else { - event.offsetLocation(offsetX, offsetY); - handled = child.dispatchGenericMotionEvent(event); - event.offsetLocation(-offsetX, -offsetY); - } + // Recycle the copy of the event that we made. + if (eventNoHistory != event) { + eventNoHistory.recycle(); + } - if (handled) { - return true; - } + // Send hover exit to the view group. If there was a child, we will already have + // sent the hover exit to it. + if (action == MotionEvent.ACTION_HOVER_EXIT) { + handled |= super.dispatchHoverEvent(event); + } + + // Done. + return handled; + } + + private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) { + if (event.getHistorySize() == 0) { + return event; + } + return MotionEvent.obtainNoHistory(event); + } + + /** @hide */ + @Override + protected boolean dispatchGenericPointerEvent(MotionEvent event) { + // Send the event to the child under the pointer. + final int childrenCount = mChildrenCount; + if (childrenCount != 0) { + final View[] children = mChildren; + final float x = event.getX(); + final float y = event.getY(); + + for (int i = childrenCount - 1; i >= 0; i--) { + final View child = children[i]; + if (!canViewReceivePointerEvents(child) + || !isTransformedTouchPointInView(x, y, child, null)) { + continue; } - } - // No child handled the event. Send it to this view group. - return super.dispatchGenericMotionEvent(event); + if (dispatchTransformedGenericPointerEvent(event, child)) { + return true; + } + } } + // No child handled the event. Send it to this view group. + return super.dispatchGenericPointerEvent(event); + } + + /** @hide */ + @Override + protected boolean dispatchGenericFocusedEvent(MotionEvent event) { // Send the event to the focused child or to this view group if it has focus. if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { - return super.dispatchGenericMotionEvent(event); + return super.dispatchGenericFocusedEvent(event); } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { return mFocused.dispatchGenericMotionEvent(event); } @@ -1201,6 +1284,33 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** + * Dispatches a generic pointer event to a child, taking into account + * transformations that apply to the child. + * + * @param event The event to send. + * @param child The view to send the event to. + * @return {@code true} if the child handled the event. + */ + private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) { + final float offsetX = mScrollX - child.mLeft; + final float offsetY = mScrollY - child.mTop; + + boolean handled; + if (!child.hasIdentityMatrix()) { + MotionEvent transformedEvent = MotionEvent.obtain(event); + transformedEvent.offsetLocation(offsetX, offsetY); + transformedEvent.transform(child.getInverseMatrix()); + handled = child.dispatchGenericMotionEvent(transformedEvent); + transformedEvent.recycle(); + } else { + event.offsetLocation(offsetX, offsetY); + handled = child.dispatchGenericMotionEvent(event); + event.offsetLocation(-offsetX, -offsetY); + } + return handled; + } + + /** * {@inheritDoc} */ @Override @@ -1213,8 +1323,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int actionMasked = action & MotionEvent.ACTION_MASK; // Handle an initial down. - if (actionMasked == MotionEvent.ACTION_DOWN - || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { + if (actionMasked == MotionEvent.ACTION_DOWN) { // Throw away all previous state when starting a new touch gesture. // The framework may have dropped the up or cancel event for the previous gesture // due to an app switch, ANR, or some other state change. @@ -1268,14 +1377,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager for (int i = childrenCount - 1; i >= 0; i--) { final View child = children[i]; - if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE - && child.getAnimation() == null) { - // Skip invisible child unless it is animating. - continue; - } - - if (!isTransformedTouchPointInView(x, y, child, null)) { - // New pointer is out of child's bounds. + if (!canViewReceivePointerEvents(child) + || !isTransformedTouchPointInView(x, y, child, null)) { continue; } @@ -1476,6 +1579,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** + * Returns true if a child view can receive pointer events. + * @hide + */ + private static boolean canViewReceivePointerEvents(View child) { + return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE + || child.getAnimation() != null; + } + + /** * Returns true if a child view contains the specified point when transformed * into its coordinate space. * Child must not be null. @@ -1975,7 +2087,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public void setPadding(int left, int top, int right, int bottom) { super.setPadding(left, top, right, bottom); - if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) { + if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) { mGroupFlags |= FLAG_PADDING_NOT_NULL; } else { mGroupFlags &= ~FLAG_PADDING_NOT_NULL; @@ -3244,6 +3356,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mTransition.removeChild(this, view); } + if (view == mHoveredChild) { + mHoveredChild = null; + } + boolean clearChildFocus = false; if (view == mFocused) { view.clearFocusForRemoval(); @@ -3307,6 +3423,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener; final boolean notifyListener = onHierarchyChangeListener != null; final View focused = mFocused; + final View hoveredChild = mHoveredChild; final boolean detach = mAttachInfo != null; View clearChildFocus = null; @@ -3320,6 +3437,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mTransition.removeChild(this, view); } + if (view == hoveredChild) { + mHoveredChild = null; + } + if (view == focused) { view.clearFocusForRemoval(); clearChildFocus = view; @@ -3377,6 +3498,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final OnHierarchyChangeListener listener = mOnHierarchyChangeListener; final boolean notify = listener != null; final View focused = mFocused; + final View hoveredChild = mHoveredChild; final boolean detach = mAttachInfo != null; View clearChildFocus = null; @@ -3389,6 +3511,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mTransition.removeChild(this, view); } + if (view == hoveredChild) { + mHoveredChild = null; + } + if (view == focused) { view.clearFocusForRemoval(); clearChildFocus = view; diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 7d6e18f..3c386b4 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -501,7 +501,12 @@ public final class ViewRoot extends Handler implements ViewParent, final boolean hardwareAccelerated = (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; - if (attrs != null && hardwareAccelerated) { + if (hardwareAccelerated) { + if (!HardwareRenderer.isAvailable()) { + mAttachInfo.mHardwareAccelerationRequested = true; + return; + } + // Only enable hardware acceleration if we are not in the system process // The window manager creates ViewRoots to display animated preview windows // of launching apps and we don't want those to be hardware accelerated @@ -524,8 +529,6 @@ public final class ViewRoot extends Handler implements ViewParent, mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent); mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested = mAttachInfo.mHardwareRenderer != null; - } else if (HardwareRenderer.isAvailable()) { - mAttachInfo.mHardwareAccelerationRequested = true; } } } diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index fc61700..9af19b8 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -159,7 +159,12 @@ public final class AccessibilityEvent implements Parcelable { * * @see #getBeforeText() * @see #getText() + * </br> + * Note: This constant is no longer needed since there + * is no limit on the length of text that is contained + * in an accessibility event anymore. */ + @Deprecated public static final int MAX_TEXT_LENGTH = 500; /** diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index e644045..dd2d00d 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -644,7 +644,7 @@ public class BaseInputConnection implements InputConnection { lp.println("Composing text:"); TextUtils.dumpSpans(text, lp, " "); } - + // Position the cursor appropriately, so that after replacing the // desired range of text it will be located in the correct spot. // This allows us to deal with filters performing edits on the text diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java index 4d9d51e..690ea85 100644 --- a/core/java/android/view/inputmethod/InputConnectionWrapper.java +++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java @@ -58,8 +58,7 @@ public class InputConnectionWrapper implements InputConnection { return mTarget.getCursorCapsMode(reqModes); } - public ExtractedText getExtractedText(ExtractedTextRequest request, - int flags) { + public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { return mTarget.getExtractedText(request, flags); } diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index 32eec9f..1f7441d 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -322,7 +322,12 @@ public final class InputMethodInfo implements Parcelable { InputMethodInfo obj = (InputMethodInfo) o; return mId.equals(obj.mId); } - + + @Override + public int hashCode() { + return mId.hashCode(); + } + /** * Used to package this object into a {@link Parcel}. * diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index c7a7374..6306274 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -1043,13 +1043,16 @@ class BrowserFrame extends Handler { // These ids need to be in sync with enum rawResId in PlatformBridge.h private static final int NODOMAIN = 1; private static final int LOADERROR = 2; - private static final int DRAWABLEDIR = 3; + /* package */ static final int DRAWABLEDIR = 3; private static final int FILE_UPLOAD_LABEL = 4; private static final int RESET_LABEL = 5; private static final int SUBMIT_LABEL = 6; private static final int FILE_UPLOAD_NO_FILE_CHOSEN = 7; - String getRawResFilename(int id) { + private String getRawResFilename(int id) { + return getRawResFilename(id, mContext); + } + /* package */ static String getRawResFilename(int id, Context context) { int resid; switch (id) { case NODOMAIN: @@ -1066,19 +1069,19 @@ class BrowserFrame extends Handler { break; case FILE_UPLOAD_LABEL: - return mContext.getResources().getString( + return context.getResources().getString( com.android.internal.R.string.upload_file); case RESET_LABEL: - return mContext.getResources().getString( + return context.getResources().getString( com.android.internal.R.string.reset); case SUBMIT_LABEL: - return mContext.getResources().getString( + return context.getResources().getString( com.android.internal.R.string.submit); case FILE_UPLOAD_NO_FILE_CHOSEN: - return mContext.getResources().getString( + return context.getResources().getString( com.android.internal.R.string.no_file_chosen); default: @@ -1086,7 +1089,7 @@ class BrowserFrame extends Handler { return ""; } TypedValue value = new TypedValue(); - mContext.getResources().getValue(resid, value, true); + context.getResources().getValue(resid, value, true); if (id == DRAWABLEDIR) { String path = value.string.toString(); int index = path.lastIndexOf('/'); diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java index ccf3d6b..7c0e478 100644 --- a/core/java/android/webkit/WebHistoryItem.java +++ b/core/java/android/webkit/WebHistoryItem.java @@ -90,9 +90,7 @@ public class WebHistoryItem implements Cloneable { * another item, the identifiers will be the same even if they are not the * same object. * @return The id for this item. - * @deprecated This method is now obsolete. */ - @Deprecated public int getId() { return mId; } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 2b507fd..71d6080 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -43,10 +43,8 @@ public class WebSettings { * SINGLE_COLUMN moves all content into one column that is the width of the * view. * NARROW_COLUMNS makes all columns no wider than the screen if possible. - * @deprecated This enum is now obsolete. */ // XXX: These must match LayoutAlgorithm in Settings.h in WebCore. - @Deprecated public enum LayoutAlgorithm { NORMAL, SINGLE_COLUMN, @@ -512,18 +510,14 @@ public class WebSettings { /** * Enables dumping the pages navigation cache to a text file. - * @deprecated This method is now obsolete. */ - @Deprecated public void setNavDump(boolean enabled) { mNavDump = enabled; } /** * Returns true if dumping the navigation cache is enabled. - * @deprecated This method is now obsolete. */ - @Deprecated public boolean getNavDump() { return mNavDump; } @@ -661,9 +655,7 @@ public class WebSettings { * Set whether the WebView uses its background for over scroll background. * If true, it will use the WebView's background. If false, it will use an * internal pattern. Default is true. - * @deprecated This method is now obsolete. */ - @Deprecated public void setUseWebViewBackgroundForOverscrollBackground(boolean view) { mUseWebViewBackgroundForOverscroll = view; } @@ -671,9 +663,7 @@ public class WebSettings { /** * Returns true if this WebView uses WebView's background instead of * internal pattern for over scroll background. - * @deprecated This method is now obsolete. */ - @Deprecated public boolean getUseWebViewBackgroundForOverscrollBackground() { return mUseWebViewBackgroundForOverscroll; } @@ -876,9 +866,7 @@ public class WebSettings { * WebView. * @param l A LayoutAlgorithm enum specifying the algorithm to use. * @see WebSettings.LayoutAlgorithm - * @deprecated This method is now obsolete. */ - @Deprecated public synchronized void setLayoutAlgorithm(LayoutAlgorithm l) { // XXX: This will only be affective if libwebcore was built with // ANDROID_LAYOUT defined. @@ -893,9 +881,7 @@ public class WebSettings { * @return LayoutAlgorithm enum value describing the layout algorithm * being used. * @see WebSettings.LayoutAlgorithm - * @deprecated This method is now obsolete. */ - @Deprecated public synchronized LayoutAlgorithm getLayoutAlgorithm() { return mLayoutAlgorithm; } diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java index 0f24edc..7f4f103 100644 --- a/core/java/android/webkit/WebTextView.java +++ b/core/java/android/webkit/WebTextView.java @@ -51,8 +51,8 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodManager; import android.widget.AbsoluteLayout.LayoutParams; import android.widget.AdapterView; import android.widget.ArrayAdapter; @@ -515,7 +515,6 @@ import junit.framework.Assert; int candEnd = EditableInputConnection.getComposingSpanEnd(sp); imm.updateSelection(this, selStart, selEnd, candStart, candEnd); } - updateCursorControllerPositions(); } @Override diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index a3ced9e..e7f8796 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -27,6 +27,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.res.AssetManager; import android.content.res.Configuration; import android.database.DataSetObserver; import android.graphics.Bitmap; @@ -853,17 +854,13 @@ public class WebView extends AbsoluteLayout private PictureListener mPictureListener; /** * Interface to listen for new pictures as they change. - * @deprecated This interface is now obsolete. */ - @Deprecated public interface PictureListener { /** * Notify the listener that the picture has changed. * @param view The WebView that owns the picture. * @param picture The new picture. - * @deprecated This method is now obsolete. */ - @Deprecated public void onNewPicture(WebView view, Picture picture); } @@ -1510,9 +1507,7 @@ public class WebView extends AbsoluteLayout /** * Enables platform notifications of data state and proxy changes. - * @deprecated Obsolete - platform notifications are always enabled. */ - @Deprecated public static void enablePlatformNotifications() { Network.enablePlatformNotifications(); } @@ -1520,9 +1515,7 @@ public class WebView extends AbsoluteLayout /** * If platform notifications are enabled, this should be called * from the Activity's onPause() or onStop(). - * @deprecated Obsolete - platform notifications are always enabled. */ - @Deprecated public static void disablePlatformNotifications() { Network.disablePlatformNotifications(); } @@ -1625,9 +1618,7 @@ public class WebView extends AbsoluteLayout * @param dest The file to store the serialized picture data. Will be * overwritten with this WebView's picture data. * @return True if the picture was successfully saved. - * @deprecated This method is now obsolete. */ - @Deprecated public boolean savePicture(Bundle b, final File dest) { if (dest == null || b == null) { return false; @@ -1689,9 +1680,7 @@ public class WebView extends AbsoluteLayout * @param b A Bundle containing the saved display data. * @param src The file where the picture data was stored. * @return True if the picture was successfully restored. - * @deprecated This method is now obsolete. */ - @Deprecated public boolean restorePicture(Bundle b, File src) { if (src == null || b == null) { return false; @@ -3634,9 +3623,7 @@ public class WebView extends AbsoluteLayout * Set the Picture listener. This is an interface used to receive * notifications of a new Picture. * @param listener An implementation of WebView.PictureListener. - * @deprecated This method is now obsolete. */ - @Deprecated public void setPictureListener(PictureListener listener) { mPictureListener = listener; } @@ -4995,9 +4982,7 @@ public class WebView extends AbsoluteLayout /** * Use this method to put the WebView into text selection mode. * Do not rely on this functionality; it will be deprecated in the future. - * @deprecated This method is now obsolete. */ - @Deprecated public void emulateShiftHeld() { setUpSelect(false, 0, 0); } @@ -7750,7 +7735,10 @@ public class WebView extends AbsoluteLayout } case WEBCORE_INITIALIZED_MSG_ID: // nativeCreate sets mNativeClass to a non-zero value - nativeCreate(msg.arg1); + String drawableDir = BrowserFrame.getRawResFilename( + BrowserFrame.DRAWABLEDIR, mContext); + AssetManager am = mContext.getAssets(); + nativeCreate(msg.arg1, drawableDir, am); break; case UPDATE_TEXTFIELD_TEXT_MSG_ID: // Make sure that the textfield is currently focused @@ -8574,10 +8562,6 @@ public class WebView extends AbsoluteLayout mWebViewCore.sendMessage(EventHub.SET_BACKGROUND_COLOR, color); } - /** - * @deprecated This method is now obsolete. - */ - @Deprecated public void debugDump() { nativeDebugDump(); mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE); @@ -8645,7 +8629,7 @@ public class WebView extends AbsoluteLayout private native Rect nativeCacheHitNodeBounds(); private native int nativeCacheHitNodePointer(); /* package */ native void nativeClearCursor(); - private native void nativeCreate(int ptr); + private native void nativeCreate(int ptr, String drawableDir, AssetManager am); private native int nativeCursorFramePointer(); private native Rect nativeCursorNodeBounds(); private native int nativeCursorNodePointer(); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index d39271e..6cb5c35 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -4529,8 +4529,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * Otherwise resurrects the selection and returns true if resurrected. */ boolean resurrectSelectionIfNeeded() { - if (mSelectedPosition < 0) { - return resurrectSelection(); + if (mSelectedPosition < 0 && resurrectSelection()) { + updateSelectorState(); + return true; } return false; } diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 0da73a4..2621e64 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -201,7 +201,8 @@ public abstract class AbsSeekBar extends ProgressBar { } @Override - void onProgressRefresh(float scale, boolean fromUser) { + void onProgressRefresh(float scale, boolean fromUser) { + super.onProgressRefresh(scale, fromUser); Drawable thumb = mThumb; if (thumb != null) { setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE); diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 1d442db..7210e21 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -410,74 +410,28 @@ public class DatePicker extends FrameLayout { } /** - * Reorders the spinners according to the date format in the current - * {@link Locale}. + * Reorders the spinners according to the date format that is + * explicitly set by the user and if no such is set fall back + * to the current locale's default format. */ private void reorderSpinners() { - java.text.DateFormat format; - String order; - - /* - * If the user is in a locale where the medium date format is still - * numeric (Japanese and Czech, for example), respect the date format - * order setting. Otherwise, use the order that the locale says is - * appropriate for a spelled-out date. - */ - - if (getShortMonths()[0].startsWith("1")) { - format = DateFormat.getDateFormat(getContext()); - } else { - format = DateFormat.getMediumDateFormat(getContext()); - } - - if (format instanceof SimpleDateFormat) { - order = ((SimpleDateFormat) format).toPattern(); - } else { - // Shouldn't happen, but just in case. - order = new String(DateFormat.getDateFormatOrder(getContext())); - } - - /* - * Remove the 3 spinners from their parent and then add them back in the - * required order. - */ - LinearLayout parent = mSpinners; - parent.removeAllViews(); - - boolean quoted = false; - boolean didDay = false, didMonth = false, didYear = false; - - for (int i = 0; i < order.length(); i++) { - char c = order.charAt(i); - - if (c == '\'') { - quoted = !quoted; - } - - if (!quoted) { - if (c == DateFormat.DATE && !didDay) { - parent.addView(mDaySpinner); - didDay = true; - } else if ((c == DateFormat.MONTH || c == 'L') && !didMonth) { - parent.addView(mMonthSpinner); - didMonth = true; - } else if (c == DateFormat.YEAR && !didYear) { - parent.addView(mYearSpinner); - didYear = true; - } + mSpinners.removeAllViews(); + char[] order = DateFormat.getDateFormatOrder(getContext()); + for (int i = 0; i < order.length; i++) { + switch (order[i]) { + case DateFormat.DATE: + mSpinners.addView(mDaySpinner); + break; + case DateFormat.MONTH: + mSpinners.addView(mMonthSpinner); + break; + case DateFormat.YEAR: + mSpinners.addView(mYearSpinner); + break; + default: + throw new IllegalArgumentException(); } } - - // Shouldn't happen, but just in case. - if (!didMonth) { - parent.addView(mMonthSpinner); - } - if (!didDay) { - parent.addView(mDaySpinner); - } - if (!didYear) { - parent.addView(mYearSpinner); - } } /** diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index cf72ec4..8db34d9 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -16,6 +16,8 @@ package android.widget; +import com.android.internal.R; + import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -41,6 +43,8 @@ import android.view.Gravity; import android.view.RemotableViewMethod; import android.view.View; import android.view.ViewDebug; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -49,8 +53,6 @@ import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; import android.widget.RemoteViews.RemoteView; -import com.android.internal.R; - /** * <p> @@ -125,6 +127,7 @@ import com.android.internal.R; public class ProgressBar extends View { private static final int MAX_LEVEL = 10000; private static final int ANIMATION_RESOLUTION = 200; + private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200; int mMinWidth; int mMaxWidth; @@ -156,6 +159,8 @@ public class ProgressBar extends View { private int mAnimationResolution; + private AccessibilityEventSender mAccessibilityEventSender; + /** * Create a new progress bar with range 0...100 and initial progress of 0. * @param context the application environment @@ -542,8 +547,11 @@ public class ProgressBar extends View { onProgressRefresh(scale, fromUser); } } - - void onProgressRefresh(float scale, boolean fromUser) { + + void onProgressRefresh(float scale, boolean fromUser) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { + scheduleAccessibilityEventSender(); + } } private synchronized void refreshProgress(int id, int progress, boolean fromUser) { @@ -1007,8 +1015,48 @@ public class ProgressBar extends View { if (mIndeterminate) { stopAnimation(); } + if(mRefreshProgressRunnable != null) { + removeCallbacks(mRefreshProgressRunnable); + } + if (mAccessibilityEventSender != null) { + removeCallbacks(mAccessibilityEventSender); + } // This should come after stopAnimation(), otherwise an invalidate message remains in the // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation super.onDetachedFromWindow(); } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + if (!super.dispatchPopulateAccessibilityEvent(event)) { + event.setItemCount(mMax); + event.setCurrentItemIndex(mProgress); + } + return true; + } + + /** + * Schedule a command for sending an accessibility event. + * </br> + * Note: A command is used to ensure that accessibility events + * are sent at most one in a given time frame to save + * system resources while the progress changes quickly. + */ + private void scheduleAccessibilityEventSender() { + if (mAccessibilityEventSender == null) { + mAccessibilityEventSender = new AccessibilityEventSender(); + } else { + removeCallbacks(mAccessibilityEventSender); + } + postDelayed(mAccessibilityEventSender, TIMEOUT_SEND_ACCESSIBILITY_EVENT); + } + + /** + * Command for sending an accessibility event. + */ + private class AccessibilityEventSender implements Runnable { + public void run() { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + } + } } diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index 1c0a2bb..365133b 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -29,6 +29,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -156,13 +157,16 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback // create in response to this bind factory.onDataSetChanged(); } - } catch (Exception e) { + } catch (RemoteException e) { Log.e(TAG, "Error notifying factory of data set changed in " + "onServiceConnected(): " + e.getMessage()); // Return early to prevent anything further from being notified // (effectively nothing has changed) return; + } catch (RuntimeException e) { + Log.e(TAG, "Error notifying factory of data set changed in " + + "onServiceConnected(): " + e.getMessage()); } // Request meta data so that we have up to date data when calling back to @@ -777,7 +781,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback tmpMetaData.count = count; tmpMetaData.setLoadingViewTemplates(loadingView, firstView); } - } catch (Exception e) { + } catch(RemoteException e) { processException("updateMetaData", e); } } @@ -792,12 +796,15 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback try { remoteViews = factory.getViewAt(position); itemId = factory.getItemId(position); - } catch (Exception e) { + } catch (RemoteException e) { Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + e.getMessage()); // Return early to prevent additional work in re-centering the view cache, and // swapping from the loading view return; + } catch (RuntimeException e) { + Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + e.getMessage()); + return; } if (remoteViews == null) { @@ -971,18 +978,20 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback return getCount() <= 0; } - private void onNotifyDataSetChanged() { // Complete the actual notifyDataSetChanged() call initiated earlier IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory(); try { factory.onDataSetChanged(); - } catch (Exception e) { + } catch (RemoteException e) { Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage()); // Return early to prevent from further being notified (since nothing has // changed) return; + } catch (RuntimeException e) { + Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage()); + return; } // Flush the cache so that we can reload new items from the service diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java index e0b08d4..7ba4777 100644 --- a/core/java/android/widget/RemoteViewsService.java +++ b/core/java/android/widget/RemoteViewsService.java @@ -138,34 +138,87 @@ public abstract class RemoteViewsService extends Service { return mIsCreated; } public synchronized void onDataSetChanged() { - mFactory.onDataSetChanged(); + try { + mFactory.onDataSetChanged(); + } catch (Exception ex) { + Thread t = Thread.currentThread(); + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); + } } public synchronized int getCount() { - return mFactory.getCount(); + int count = 0; + try { + count = mFactory.getCount(); + } catch (Exception ex) { + Thread t = Thread.currentThread(); + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); + } + return count; } public synchronized RemoteViews getViewAt(int position) { - RemoteViews rv = mFactory.getViewAt(position); - rv.setIsWidgetCollectionChild(true); + RemoteViews rv = null; + try { + rv = mFactory.getViewAt(position); + if (rv != null) { + rv.setIsWidgetCollectionChild(true); + } + } catch (Exception ex) { + Thread t = Thread.currentThread(); + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); + } return rv; } public synchronized RemoteViews getLoadingView() { - return mFactory.getLoadingView(); + RemoteViews rv = null; + try { + rv = mFactory.getLoadingView(); + } catch (Exception ex) { + Thread t = Thread.currentThread(); + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); + } + return rv; } public synchronized int getViewTypeCount() { - return mFactory.getViewTypeCount(); + int count = 0; + try { + count = mFactory.getViewTypeCount(); + } catch (Exception ex) { + Thread t = Thread.currentThread(); + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); + } + return count; } public synchronized long getItemId(int position) { - return mFactory.getItemId(position); + long id = 0; + try { + id = mFactory.getItemId(position); + } catch (Exception ex) { + Thread t = Thread.currentThread(); + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); + } + return id; } public synchronized boolean hasStableIds() { - return mFactory.hasStableIds(); + boolean hasStableIds = false; + try { + hasStableIds = mFactory.hasStableIds(); + } catch (Exception ex) { + Thread t = Thread.currentThread(); + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); + } + return hasStableIds; } public void onDestroy(Intent intent) { synchronized (sLock) { Intent.FilterComparison fc = new Intent.FilterComparison(intent); if (RemoteViewsService.sRemoteViewFactories.containsKey(fc)) { RemoteViewsFactory factory = RemoteViewsService.sRemoteViewFactories.get(fc); - factory.onDestroy(); + try { + factory.onDestroy(); + } catch (Exception ex) { + Thread t = Thread.currentThread(); + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); + } RemoteViewsService.sRemoteViewFactories.remove(fc); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 13b9285f..baf20a1 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -43,6 +43,7 @@ import android.inputmethodservice.ExtractEditText; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; @@ -81,6 +82,7 @@ import android.text.method.TextKeyListener; import android.text.method.TimeKeyListener; import android.text.method.TransformationMethod; import android.text.style.ClickableSpan; +import android.text.style.CorrectionSpan; import android.text.style.ParagraphStyle; import android.text.style.URLSpan; import android.text.style.UpdateAppearance; @@ -3977,13 +3979,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener observer.removeOnPreDrawListener(this); mPreDrawState = PREDRAW_NOT_REGISTERED; } - // No need to create the controller, as getXXController would. - if (mInsertionPointCursorController != null) { - observer.removeOnTouchModeChangeListener(mInsertionPointCursorController); - } - if (mSelectionModifierCursorController != null) { - observer.removeOnTouchModeChangeListener(mSelectionModifierCursorController); - } if (mError != null) { hideError(); @@ -4210,6 +4205,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected void onDraw(Canvas canvas) { + if (mPreDrawState == PREDRAW_DONE) { + final ViewTreeObserver observer = getViewTreeObserver(); + observer.removeOnPreDrawListener(this); + mPreDrawState = PREDRAW_NOT_REGISTERED; + } + if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return; restartMarqueeIfNeeded(); @@ -4281,12 +4282,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (mPreDrawState == PREDRAW_DONE) { - final ViewTreeObserver observer = getViewTreeObserver(); - observer.removeOnPreDrawListener(this); - mPreDrawState = PREDRAW_NOT_REGISTERED; - } - int color = mCurTextColor; if (mLayout == null) { @@ -4549,15 +4544,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (translate) canvas.translate(0, -cursorOffsetVertical); } - /** - * Update the positions of the CursorControllers. Needed by WebTextView, - * which does not draw. - * @hide - */ - protected void updateCursorControllerPositions() { - // TODO remove - } - @Override public void getFocusedRect(Rect r) { if (mLayout == null) { @@ -5236,6 +5222,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @param text The auto complete text the user has selected. */ public void onCommitCompletion(CompletionInfo text) { + // intentionally empty } /** @@ -5422,6 +5409,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * of edit operations through a call to link {@link #beginBatchEdit()}. */ public void onBeginBatchEdit() { + // intentionally empty } /** @@ -5429,6 +5417,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * of edit operations through a call to link {@link #endBatchEdit}. */ public void onEndBatchEdit() { + // intentionally empty } /** @@ -6275,15 +6264,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (isFocused()) { - // This offsets because getInterestingRect() is in terms of - // viewport coordinates, but requestRectangleOnScreen() - // is in terms of content coordinates. + // This offsets because getInterestingRect() is in terms of viewport coordinates, but + // requestRectangleOnScreen() is in terms of content coordinates. - Rect r = new Rect(x, top, x + 1, bottom); - getInterestingRect(r, line); - r.offset(mScrollX, mScrollY); + if (mTempRect == null) mTempRect = new Rect(); + mTempRect.set(x, top, x + 1, bottom); + getInterestingRect(mTempRect, line); + mTempRect.offset(mScrollX, mScrollY); - if (requestRectangleOnScreen(r)) { + if (requestRectangleOnScreen(mTempRect)) { changed = true; } } @@ -6756,25 +6745,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * This method is called when the text is changed, in case any - * subclasses would like to know. + * This method is called when the text is changed, in case any subclasses + * would like to know. * - * @param text The text the TextView is displaying. - * @param start The offset of the start of the range of the text - * that was modified. - * @param before The offset of the former end of the range of the - * text that was modified. If text was simply inserted, - * this will be the same as <code>start</code>. - * If text was replaced with new text or deleted, the - * length of the old text was <code>before-start</code>. - * @param after The offset of the end of the range of the text - * that was modified. If text was simply deleted, - * this will be the same as <code>start</code>. - * If text was replaced with new text or inserted, - * the length of the new text is <code>after-start</code>. + * Within <code>text</code>, the <code>lengthAfter</code> characters + * beginning at <code>start</code> have just replaced old text that had + * length <code>lengthBefore</code>. It is an error to attempt to make + * changes to <code>text</code> from this callback. + * + * @param text The text the TextView is displaying + * @param start The offset of the start of the range of the text that was + * modified + * @param lengthBefore The length of the former text that has been replaced + * @param lengthAfter The length of the replacement modified text */ - protected void onTextChanged(CharSequence text, - int start, int before, int after) { + protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + // intentionally empty } /** @@ -6785,6 +6771,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @param selEnd The new selection end location. */ protected void onSelectionChanged(int selStart, int selEnd) { + // intentionally empty } /** @@ -7326,9 +7313,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && mText instanceof Spannable && mLayout != null) { boolean handled = false; - final int oldScrollX = mScrollX; - final int oldScrollY = mScrollY; - if (mMovement != null) { handled |= mMovement.onTouchEvent(this, (Spannable) mText, event); } @@ -7345,27 +7329,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (isTextEditable() || mTextIsSelectable) { - if (mScrollX != oldScrollX || mScrollY != oldScrollY) { // TODO remove - // Hide insertion anchor while scrolling. Leave selection. - hideInsertionPointCursorController(); // TODO any motion should hide it + if ((isTextEditable() || mTextIsSelectable) && touchIsFinished) { + // Show the IME, except when selecting in read-only text. + if (!mTextIsSelectable) { + final InputMethodManager imm = InputMethodManager.peekInstance(); + handled |= imm != null && imm.showSoftInput(this, 0); } - if (touchIsFinished) { - // Show the IME, except when selecting in read-only text. - if (!mTextIsSelectable) { - final InputMethodManager imm = InputMethodManager.peekInstance(); - handled |= imm != null && imm.showSoftInput(this, 0); - } - - boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect(); - if (!selectAllGotFocus && hasSelection()) { - startSelectionActionMode(); - } else { - stopSelectionActionMode(); - if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) { - getInsertionController().show(); - } + boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect(); + if (!selectAllGotFocus && hasSelection()) { + startSelectionActionMode(); + } else { + stopSelectionActionMode(); + if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) { + getInsertionController().show(); } } } @@ -7913,9 +7890,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener text = getHint(); } if (!TextUtils.isEmpty(text)) { - if (text.length() > AccessibilityEvent.MAX_TEXT_LENGTH) { - text = text.subSequence(0, AccessibilityEvent.MAX_TEXT_LENGTH + 1); - } event.getText().add(text); } } else { @@ -8180,7 +8154,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int offset = getOffset(mLastDownPositionX, mLastDownPositionY); stopSelectionActionMode(); Selection.setSelection((Spannable)mText, offset); - getInsertionController().show(0); + getInsertionController().showWithPaste(); handled = true; } @@ -8453,55 +8427,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - /** - * A CursorController instance can be used to control a cursor in the text. - * It is not used outside of {@link TextView}. - * @hide - */ - private interface CursorController extends ViewTreeObserver.OnTouchModeChangeListener { - /** - * Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}. - * See also {@link #hide()}. - */ - public void show(); - - /** - * Hide the cursor controller from screen. - * See also {@link #show()}. - */ - public void hide(); - - /** - * @return true if the CursorController is currently visible - */ - public boolean isShowing(); - - /** - * Update the controller's position. - */ - public void updatePosition(HandleView handle, int x, int y); - - public void updateOffset(HandleView handle, int offset); - - public void updatePosition(); - - public int getCurrentOffset(HandleView handle); - - /** - * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller - * a chance to become active and/or visible. - * @param event The touch event - */ - public boolean onTouchEvent(MotionEvent event); - - /** - * Called when the view is detached from window. Perform house keeping task, such as - * stopping Runnable thread that would otherwise keep a reference on the context, thus - * preventing the activity to be recycled. - */ - public void onDetached(); - } - private class PastePopupMenu implements OnClickListener { private final PopupWindow mContainer; private int mPositionX; @@ -8637,32 +8562,43 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private class HandleView extends View implements ViewTreeObserver.OnPreDrawListener { - private Drawable mDrawable; + private abstract class HandleView extends View implements ViewTreeObserver.OnPreDrawListener { + protected Drawable mDrawable; private final PopupWindow mContainer; // Position with respect to the parent TextView private int mPositionX, mPositionY; - private final CursorController mController; private boolean mIsDragging; // Offset from touch position to mPosition private float mTouchToWindowOffsetX, mTouchToWindowOffsetY; - private float mHotspotX; + protected float mHotspotX; // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up private float mTouchOffsetY; // Where the touch position should be on the handle to ensure a maximum cursor visibility private float mIdealVerticalOffset; // Parent's (TextView) position in window private int mLastParentX, mLastParentY; - private float mDownPositionX, mDownPositionY; // PopupWindow container absolute position with respect to the enclosing window private int mContainerPositionX, mContainerPositionY; // Visible or not (scrolled off screen), whether or not this handle should be visible private boolean mIsActive = false; - // The insertion handle can have an associated PastePopupMenu - private boolean mIsInsertionHandle = false; - // Used to detect taps on the insertion handle, which will affect the PastePopupMenu - private long mTouchTimer; - private PastePopupMenu mPastePopupWindow; + + public HandleView() { + super(TextView.this.mContext); + mContainer = new PopupWindow(TextView.this.mContext, null, + com.android.internal.R.attr.textSelectHandleWindowStyle); + mContainer.setSplitTouchEnabled(true); + mContainer.setClippingEnabled(false); + mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL); + mContainer.setContentView(this); + + initDrawable(); + + final int handleHeight = mDrawable.getIntrinsicHeight(); + mTouchOffsetY = -0.3f * handleHeight; + mIdealVerticalOffset = 0.7f * handleHeight; + } + + protected abstract void initDrawable(); // Touch-up filter: number of previous positions remembered private static final int HISTORY_SIZE = 5; @@ -8703,73 +8639,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (i > 0 && i < iMax && (now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) { - mController.updateOffset(this, mPreviousOffsets[index]); + updateOffset(mPreviousOffsets[index]); } } - public static final int LEFT = 0; - public static final int CENTER = 1; - public static final int RIGHT = 2; - - public HandleView(CursorController controller, int pos) { - super(TextView.this.mContext); - mController = controller; - mContainer = new PopupWindow(TextView.this.mContext, null, - com.android.internal.R.attr.textSelectHandleWindowStyle); - mContainer.setSplitTouchEnabled(true); - mContainer.setClippingEnabled(false); - mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL); - mContainer.setContentView(this); - - setPosition(pos); - } - - private void setPosition(int pos) { - int handleWidth; - switch (pos) { - case LEFT: { - if (mSelectHandleLeft == null) { - mSelectHandleLeft = mContext.getResources().getDrawable( - mTextSelectHandleLeftRes); - } - mDrawable = mSelectHandleLeft; - handleWidth = mDrawable.getIntrinsicWidth(); - mHotspotX = handleWidth * 3.0f / 4.0f; - break; - } - - case RIGHT: { - if (mSelectHandleRight == null) { - mSelectHandleRight = mContext.getResources().getDrawable( - mTextSelectHandleRightRes); - } - mDrawable = mSelectHandleRight; - handleWidth = mDrawable.getIntrinsicWidth(); - mHotspotX = handleWidth / 4.0f; - break; - } - - case CENTER: - default: { - if (mSelectHandleCenter == null) { - mSelectHandleCenter = mContext.getResources().getDrawable( - mTextSelectHandleRes); - } - mDrawable = mSelectHandleCenter; - handleWidth = mDrawable.getIntrinsicWidth(); - mHotspotX = handleWidth / 2.0f; - mIsInsertionHandle = true; - break; - } - } - - final int handleHeight = mDrawable.getIntrinsicHeight(); - mTouchOffsetY = -0.3f * handleHeight; - mIdealVerticalOffset = 0.7f * handleHeight; - - invalidate(); - } - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()); @@ -8781,7 +8654,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mContainer.update(mContainerPositionX, mContainerPositionY, mRight - mLeft, mBottom - mTop); - hidePastePopupWindow(); + hideAssociatedPopupWindow(); } else { mContainer.showAtLocation(TextView.this, 0, mContainerPositionX, mContainerPositionY); @@ -8793,10 +8666,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private void dismiss() { + protected void dismiss() { mIsDragging = false; mContainer.dismiss(); - hidePastePopupWindow(); + hideAssociatedPopupWindow(); } public void hide() { @@ -8829,9 +8702,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final TextView hostView = TextView.this; - if (mTempRect == null) { - mTempRect = new Rect(); - } + if (mTempRect == null) mTempRect = new Rect(); final Rect clip = mTempRect; clip.left = compoundPaddingLeft; clip.top = extendedPaddingTop; @@ -8865,18 +8736,42 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mLastParentX = mTempCoords[0]; mLastParentY = mTempCoords[1]; } - // Hide paste popup window as soon as the handle is dragged. - hidePastePopupWindow(); + + hideAssociatedPopupWindow(); } } + public abstract int getCurrentCursorOffset(); + + public abstract void updateOffset(int offset); + + public abstract void updatePosition(int x, int y); + + protected void positionAtCursorOffset(int offset) { + addPositionToTouchUpFilter(offset); + final int width = mDrawable.getIntrinsicWidth(); + final int height = mDrawable.getIntrinsicHeight(); + final int line = mLayout.getLineForOffset(offset); + final int lineBottom = mLayout.getLineBottom(line); + + final Rect bounds = sCursorControllerTempRect; + bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX) + + TextView.this.mScrollX; + bounds.top = lineBottom + TextView.this.mScrollY; + + bounds.right = bounds.left + width; + bounds.bottom = bounds.top + height; + + convertFromViewportToContentCoordinates(bounds); + moveTo(bounds.left, bounds.top); + } + /** * Updates the global container's position. * @return whether or not the position has actually changed */ private boolean updateContainerPosition() { - // TODO Prevent this using different HandleView subclasses - mController.updateOffset(this, mController.getCurrentOffset(this)); + positionAtCursorOffset(getCurrentCursorOffset()); TextView.this.getLocationInWindow(mTempCoords); final int containerPositionX = mTempCoords[0] + mPositionX; final int containerPositionY = mTempCoords[1] + mPositionY; @@ -8906,7 +8801,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // Hide paste popup as soon as the view is scrolled or moved - hidePastePopupWindow(); + hideAssociatedPopupWindow(); } return true; } @@ -8921,20 +8816,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public boolean onTouchEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: { - startTouchUpFilter(mController.getCurrentOffset(this)); - mDownPositionX = ev.getRawX(); - mDownPositionY = ev.getRawY(); - mTouchToWindowOffsetX = mDownPositionX - mPositionX; - mTouchToWindowOffsetY = mDownPositionY - mPositionY; + startTouchUpFilter(getCurrentCursorOffset()); + mTouchToWindowOffsetX = ev.getRawX() - mPositionX; + mTouchToWindowOffsetY = ev.getRawY() - mPositionY; final int[] coords = mTempCoords; TextView.this.getLocationInWindow(coords); mLastParentX = coords[0]; mLastParentY = coords[1]; mIsDragging = true; - if (mIsInsertionHandle) { - mTouchTimer = SystemClock.uptimeMillis(); - } break; } @@ -8958,27 +8848,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX; final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY; - mController.updatePosition(this, Math.round(newPosX), Math.round(newPosY)); + updatePosition(Math.round(newPosX), Math.round(newPosY)); break; } case MotionEvent.ACTION_UP: - if (mIsInsertionHandle) { - long delay = SystemClock.uptimeMillis() - mTouchTimer; - if (delay < ViewConfiguration.getTapTimeout()) { - final float deltaX = mDownPositionX - ev.getRawX(); - final float deltaY = mDownPositionY - ev.getRawY(); - final float distanceSquared = deltaX * deltaX + deltaY * deltaY; - if (distanceSquared < mSquaredTouchSlopDistance) { - if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) { - // Tapping on the handle dismisses the displayed paste view, - mPastePopupWindow.hide(); - } else { - ((InsertionPointCursorController) mController).show(0); - } - } - } - } filterOnTouchUp(); mIsDragging = false; break; @@ -8994,60 +8868,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mIsDragging; } - void positionAtCursor(int offset) { - addPositionToTouchUpFilter(offset); - final int width = mDrawable.getIntrinsicWidth(); - final int height = mDrawable.getIntrinsicHeight(); - final int line = mLayout.getLineForOffset(offset); - final int lineBottom = mLayout.getLineBottom(line); - - final Rect bounds = sCursorControllerTempRect; - bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX) + - TextView.this.mScrollX; - bounds.top = lineBottom + TextView.this.mScrollY; - - bounds.right = bounds.left + width; - bounds.bottom = bounds.top + height; - - convertFromViewportToContentCoordinates(bounds); - moveTo(bounds.left, bounds.top); - } - - void showPastePopupWindow() { - if (mIsInsertionHandle) { - if (mPastePopupWindow == null) { - // Lazy initialisation: create when actually shown only. - mPastePopupWindow = new PastePopupMenu(); - } - mPastePopupWindow.show(); - } + void hideAssociatedPopupWindow() { + // No associated popup window by default } - - void hidePastePopupWindow() { - if (mPastePopupWindow != null) { - mPastePopupWindow.hide(); - } + + public void onDetached() { + // Should be overriden to clean possible Runnable } } - private class InsertionPointCursorController implements CursorController { + private class InsertionHandleView extends HandleView { private static final int DELAY_BEFORE_FADE_OUT = 4000; - private static final int DELAY_BEFORE_PASTE = 2000; - private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; + private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds - // The cursor controller image. Lazily created. - private HandleView mHandle; + // Used to detect taps on the insertion handle, which will affect the PastePopupMenu + private long mTouchTimer; + private float mDownPositionX, mDownPositionY; + private PastePopupMenu mPastePopupWindow; private Runnable mHider; private Runnable mPastePopupShower; - public void show() { - show(DELAY_BEFORE_PASTE); + public InsertionHandleView() { + super(); } - public void show(int delayBeforePaste) { - getHandle().show(); + @Override + public void show() { + super.show(); hideDelayed(); removePastePopupCallback(); + } + + public void show(int delayBeforePaste) { + show(); + final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime; if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION) { delayBeforePaste = 0; @@ -9056,7 +8910,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mPastePopupShower == null) { mPastePopupShower = new Runnable() { public void run() { - getHandle().showPastePopupWindow(); + showAssociatedPopupWindow(); } }; } @@ -9064,6 +8918,29 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + @Override + protected void dismiss() { + super.dismiss(); + onDetached(); + } + + @Override + public void hide() { + super.hide(); + } + + private void hideDelayed() { + removeHiderCallback(); + if (mHider == null) { + mHider = new Runnable() { + public void run() { + hide(); + } + }; + } + postDelayed(mHider, DELAY_BEFORE_FADE_OUT); + } + private void removePastePopupCallback() { if (mPastePopupShower != null) { removeCallbacks(mPastePopupShower); @@ -9076,61 +8953,232 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - public void hide() { - if (mHandle != null) { - mHandle.hide(); + @Override + protected void initDrawable() { + if (mSelectHandleCenter == null) { + mSelectHandleCenter = mContext.getResources().getDrawable( + mTextSelectHandleRes); } - removeHiderCallback(); - removePastePopupCallback(); + mDrawable = mSelectHandleCenter; + mHotspotX = mDrawable.getIntrinsicWidth() / 2.0f; } - private void hideDelayed() { - removeHiderCallback(); - if (mHider == null) { - mHider = new Runnable() { - public void run() { - hide(); + @Override + public boolean onTouchEvent(MotionEvent ev) { + final boolean result = super.onTouchEvent(ev); + + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + mDownPositionX = ev.getRawX(); + mDownPositionY = ev.getRawY(); + mTouchTimer = SystemClock.uptimeMillis(); + break; + + case MotionEvent.ACTION_UP: + long delay = SystemClock.uptimeMillis() - mTouchTimer; + if (delay < ViewConfiguration.getTapTimeout()) { + final float deltaX = mDownPositionX - ev.getRawX(); + final float deltaY = mDownPositionY - ev.getRawY(); + final float distanceSquared = deltaX * deltaX + deltaY * deltaY; + if (distanceSquared < mSquaredTouchSlopDistance) { + if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) { + // Tapping on the handle dismisses the displayed paste view, + mPastePopupWindow.hide(); + } else { + show(0); + } + } } - }; + break; + + default: + break; } - postDelayed(mHider, DELAY_BEFORE_FADE_OUT); + + return result; } - public boolean isShowing() { - return mHandle != null && mHandle.isShowing(); + @Override + public int getCurrentCursorOffset() { + return TextView.this.getSelectionStart(); } - public void updatePosition(HandleView handle, int x, int y) { - final int previousOffset = getSelectionStart(); + @Override + public void updateOffset(int offset) { + Selection.setSelection((Spannable) mText, offset); + positionAtCursorOffset(offset); + } + + @Override + public void updatePosition(int x, int y) { + final int previousOffset = getCurrentCursorOffset(); final int newOffset = getOffset(x, y); if (newOffset != previousOffset) { - updateOffset(handle, newOffset); + updateOffset(newOffset); removePastePopupCallback(); } hideDelayed(); } - public void updateOffset(HandleView handle, int offset) { - Selection.setSelection((Spannable) mText, offset); - updatePosition(); + void showAssociatedPopupWindow() { + if (mPastePopupWindow == null) { + // Lazy initialisation: create when actually shown only. + mPastePopupWindow = new PastePopupMenu(); + } + mPastePopupWindow.show(); } - public void updatePosition() { - final int offset = getSelectionStart(); + @Override + void hideAssociatedPopupWindow() { + if (mPastePopupWindow != null) { + mPastePopupWindow.hide(); + } + } - if (offset < 0) { - // Should never happen, safety check. - Log.w(LOG_TAG, "Update cursor controller position called with no cursor"); - hide(); - return; + @Override + public void onDetached() { + removeHiderCallback(); + removePastePopupCallback(); + } + } + + private class SelectionStartHandleView extends HandleView { + public SelectionStartHandleView() { + super(); + } + + @Override + protected void initDrawable() { + if (mSelectHandleLeft == null) { + mSelectHandleLeft = mContext.getResources().getDrawable( + mTextSelectHandleLeftRes); } + mDrawable = mSelectHandleLeft; + mHotspotX = mDrawable.getIntrinsicWidth() * 3.0f / 4.0f; + } + + @Override + public int getCurrentCursorOffset() { + return TextView.this.getSelectionStart(); + } + + @Override + public void updateOffset(int offset) { + Selection.setSelection((Spannable) mText, offset, getSelectionEnd()); + positionAtCursorOffset(offset); + } + + @Override + public void updatePosition(int x, int y) { + final int selectionStart = getSelectionStart(); + final int selectionEnd = getSelectionEnd(); + + int offset = getOffset(x, y); + + // No need to redraw when the offset is unchanged + if (offset == selectionStart) return; + // Handles can not cross and selection is at least one character + if (offset >= selectionEnd) offset = selectionEnd - 1; + + Selection.setSelection((Spannable) mText, offset, selectionEnd); + positionAtCursorOffset(offset); + } + } + + private class SelectionEndHandleView extends HandleView { + public SelectionEndHandleView() { + super(); + } + + @Override + protected void initDrawable() { + if (mSelectHandleRight == null) { + mSelectHandleRight = mContext.getResources().getDrawable( + mTextSelectHandleRightRes); + } + mDrawable = mSelectHandleRight; + mHotspotX = mDrawable.getIntrinsicWidth() / 4.0f; + } + + @Override + public int getCurrentCursorOffset() { + return TextView.this.getSelectionEnd(); + } + + @Override + public void updateOffset(int offset) { + Selection.setSelection((Spannable) mText, getSelectionStart(), offset); + positionAtCursorOffset(offset); + } + + @Override + public void updatePosition(int x, int y) { + final int selectionStart = getSelectionStart(); + final int selectionEnd = getSelectionEnd(); + + int offset = getOffset(x, y); + + // No need to redraw when the offset is unchanged + if (offset == selectionEnd) return; + // Handles can not cross and selection is at least one character + if (offset <= selectionStart) offset = selectionStart + 1; + + Selection.setSelection((Spannable) mText, selectionStart, offset); + positionAtCursorOffset(offset); + } + } + + /** + * A CursorController instance can be used to control a cursor in the text. + * It is not used outside of {@link TextView}. + * @hide + */ + private interface CursorController extends ViewTreeObserver.OnTouchModeChangeListener { + /** + * Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}. + * See also {@link #hide()}. + */ + public void show(); + + /** + * Hide the cursor controller from screen. + * See also {@link #show()}. + */ + public void hide(); - getHandle().positionAtCursor(offset); + /** + * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller + * a chance to become active and/or visible. + * @param event The touch event + */ + public boolean onTouchEvent(MotionEvent event); + + /** + * Called when the view is detached from window. Perform house keeping task, such as + * stopping Runnable thread that would otherwise keep a reference on the context, thus + * preventing the activity from being recycled. + */ + public void onDetached(); + } + + private class InsertionPointCursorController implements CursorController { + private static final int DELAY_BEFORE_PASTE = 2000; + + private InsertionHandleView mHandle; + + public void show() { + ((InsertionHandleView) getHandle()).show(DELAY_BEFORE_PASTE); } - public int getCurrentOffset(HandleView handle) { - return getSelectionStart(); + public void showWithPaste() { + ((InsertionHandleView) getHandle()).show(0); + } + + public void hide() { + if (mHandle != null) { + mHandle.hide(); + } } public boolean onTouchEvent(MotionEvent ev) { @@ -9145,30 +9193,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private HandleView getHandle() { if (mHandle == null) { - mHandle = new HandleView(this, HandleView.CENTER); + mHandle = new InsertionHandleView(); } return mHandle; } @Override public void onDetached() { - removeHiderCallback(); - removePastePopupCallback(); + final ViewTreeObserver observer = getViewTreeObserver(); + observer.removeOnTouchModeChangeListener(this); + + if (mHandle != null) mHandle.onDetached(); } } private class SelectionModifierCursorController implements CursorController { - // The cursor controller images, lazily created when shown. - private HandleView mStartHandle, mEndHandle; + // The cursor controller handles, lazily created when shown. + private SelectionStartHandleView mStartHandle; + private SelectionEndHandleView mEndHandle; // The offsets of that last touch down event. Remembered to start selection there. private int mMinTouchOffset, mMaxTouchOffset; - // Whether selection anchors are active - private boolean mIsShowing; // Double tap detection private long mPreviousTapUpTime = 0; - private int mPreviousTapPositionX; - private int mPreviousTapPositionY; + private int mPreviousTapPositionX, mPreviousTapPositionY; SelectionModifierCursorController() { resetTouchOffsets(); @@ -9180,10 +9228,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // Lazy object creation has to be done before updatePosition() is called. - if (mStartHandle == null) mStartHandle = new HandleView(this, HandleView.LEFT); - if (mEndHandle == null) mEndHandle = new HandleView(this, HandleView.RIGHT); - - mIsShowing = true; + if (mStartHandle == null) mStartHandle = new SelectionStartHandleView(); + if (mEndHandle == null) mEndHandle = new SelectionEndHandleView(); mStartHandle.show(); mEndHandle.show(); @@ -9194,82 +9240,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void hide() { if (mStartHandle != null) mStartHandle.hide(); if (mEndHandle != null) mEndHandle.hide(); - mIsShowing = false; - } - - public boolean isShowing() { - return mIsShowing; - } - - public void updatePosition(HandleView handle, int x, int y) { - int selectionStart = getSelectionStart(); - int selectionEnd = getSelectionEnd(); - - int offset = getOffset(x, y); - - // Handle the case where start and end are swapped, making sure start <= end - if (handle == mStartHandle) { - if (selectionStart == offset || offset > selectionEnd) { - return; // no change, no need to redraw; - } - // If the user "closes" the selection entirely they were probably trying to - // select a single character. Help them out. - if (offset == selectionEnd) { - offset = selectionEnd - 1; - } - selectionStart = offset; - } else { - if (selectionEnd == offset || offset < selectionStart) { - return; // no change, no need to redraw; - } - // If the user "closes" the selection entirely they were probably trying to - // select a single character. Help them out. - if (offset == selectionStart) { - offset = selectionStart + 1; - } - selectionEnd = offset; - } - - Selection.setSelection((Spannable) mText, selectionStart, selectionEnd); - updatePosition(); - } - - public void updateOffset(HandleView handle, int offset) { - int start = getSelectionStart(); - int end = getSelectionEnd(); - - if (mStartHandle == handle) { - start = offset; - } else { - end = offset; - } - - Selection.setSelection((Spannable) mText, start, end); - updatePosition(); - } - - public void updatePosition() { - if (!isShowing()) { - return; - } - - final int selectionStart = getSelectionStart(); - final int selectionEnd = getSelectionEnd(); - - if ((selectionStart < 0) || (selectionEnd < 0)) { - // Should never happen, safety check. - Log.w(LOG_TAG, "Update selection controller position called with no cursor"); - hide(); - return; - } - - // The handles have been created since the controller isShowing(). - mStartHandle.positionAtCursor(selectionStart); - mEndHandle.positionAtCursor(selectionEnd); - } - - public int getCurrentOffset(HandleView handle) { - return mStartHandle == handle ? getSelectionStart() : getSelectionEnd(); } public boolean onTouchEvent(MotionEvent event) { @@ -9360,7 +9330,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - public void onDetached() {} + public void onDetached() { + final ViewTreeObserver observer = getViewTreeObserver(); + observer.removeOnTouchModeChangeListener(this); + + if (mStartHandle != null) mStartHandle.onDetached(); + if (mEndHandle != null) mEndHandle.onDetached(); + } } private void hideInsertionPointCursorController() { diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index 8f1354b..11b594c 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -25,13 +25,13 @@ import com.android.internal.widget.ActionBarView; import android.animation.Animator; import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.app.ActionBar; import android.app.Activity; import android.app.Dialog; -import android.app.Fragment; import android.app.FragmentTransaction; import android.content.Context; import android.graphics.drawable.Drawable; @@ -44,7 +44,6 @@ import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.animation.DecelerateInterpolator; -import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.SpinnerAdapter; @@ -59,6 +58,7 @@ import java.util.ArrayList; * which is normally hidden. */ public class ActionBarImpl extends ActionBar { + private static final String TAG = "ActionBarImpl"; private static final int NORMAL_VIEW = 0; private static final int CONTEXT_VIEW = 1; @@ -92,60 +92,34 @@ public class ActionBarImpl extends ActionBar { final Handler mHandler = new Handler(); - private Animator mCurrentAnim; + private Animator mCurrentShowAnim; + private Animator mCurrentModeAnim; private boolean mShowHideAnimationEnabled; + boolean mWasHiddenBeforeMode; private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator(); final AnimatorListener[] mAfterAnimation = new AnimatorListener[] { - new AnimatorListener() { // NORMAL_VIEW - @Override - public void onAnimationStart(Animator animation) { - } - + new AnimatorListenerAdapter() { // NORMAL_VIEW @Override public void onAnimationEnd(Animator animation) { if (mLowerContextView != null) { mLowerContextView.removeAllViews(); } - mCurrentAnim = null; + mCurrentModeAnim = null; hideAllExcept(NORMAL_VIEW); } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } }, - new AnimatorListener() { // CONTEXT_VIEW - @Override - public void onAnimationStart(Animator animation) { - } - + new AnimatorListenerAdapter() { // CONTEXT_VIEW @Override public void onAnimationEnd(Animator animation) { - mCurrentAnim = null; + mCurrentModeAnim = null; hideAllExcept(CONTEXT_VIEW); } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } } }; - final AnimatorListener mHideListener = new AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - + final AnimatorListener mHideListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (mContentView != null) { @@ -153,36 +127,16 @@ public class ActionBarImpl extends ActionBar { } mContainerView.setVisibility(View.GONE); mContainerView.setTransitioning(false); - mCurrentAnim = null; - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { + mCurrentShowAnim = null; } }; - final AnimatorListener mShowListener = new AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - + final AnimatorListener mShowListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mCurrentAnim = null; + mCurrentShowAnim = null; mContainerView.requestLayout(); } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } }; public ActionBarImpl(Activity activity) { @@ -229,8 +183,8 @@ public class ActionBarImpl extends ActionBar { */ public void setShowHideAnimationEnabled(boolean enabled) { mShowHideAnimationEnabled = enabled; - if (!enabled && mCurrentAnim != null) { - mCurrentAnim.end(); + if (!enabled && mCurrentShowAnim != null) { + mCurrentShowAnim.end(); } } @@ -370,6 +324,7 @@ public class ActionBarImpl extends ActionBar { mUpperContextView.killMode(); ActionMode mode = new ActionModeImpl(callback); if (callback.onCreateActionMode(mode, mode.getMenu())) { + mWasHiddenBeforeMode = !isShowing(); mode.invalidate(); mUpperContextView.initForMode(mode); animateTo(CONTEXT_VIEW); @@ -378,7 +333,6 @@ public class ActionBarImpl extends ActionBar { mLowerContextView.setVisibility(View.VISIBLE); } mActionMode = mode; - show(); return mode; } return null; @@ -498,10 +452,15 @@ public class ActionBarImpl extends ActionBar { @Override public void show() { - if (mCurrentAnim != null) { - mCurrentAnim.end(); + show(true); + } + + void show(boolean markHiddenBeforeMode) { + if (mCurrentShowAnim != null) { + mCurrentShowAnim.end(); } if (mContainerView.getVisibility() == View.VISIBLE) { + if (markHiddenBeforeMode) mWasHiddenBeforeMode = false; return; } mContainerView.setVisibility(View.VISIBLE); @@ -517,17 +476,19 @@ public class ActionBarImpl extends ActionBar { b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0)); } anim.addListener(mShowListener); - mCurrentAnim = anim; + mCurrentShowAnim = anim; anim.start(); } else { + mContainerView.setAlpha(1); + mContainerView.setTranslationY(0); mShowListener.onAnimationEnd(null); } } @Override public void hide() { - if (mCurrentAnim != null) { - mCurrentAnim.end(); + if (mCurrentShowAnim != null) { + mCurrentShowAnim.end(); } if (mContainerView.getVisibility() == View.GONE) { return; @@ -545,7 +506,7 @@ public class ActionBarImpl extends ActionBar { -mContainerView.getHeight())); } anim.addListener(mHideListener); - mCurrentAnim = anim; + mCurrentShowAnim = anim; anim.start(); } else { mHideListener.onAnimationEnd(null); @@ -556,13 +517,17 @@ public class ActionBarImpl extends ActionBar { return mContainerView.getVisibility() == View.VISIBLE; } - private long animateTo(int viewIndex) { - show(); + long animateTo(int viewIndex) { + show(false); + if (mCurrentModeAnim != null) { + mCurrentModeAnim.end(); + } AnimatorSet set = new AnimatorSet(); final View targetChild = mContainerView.getChildAt(viewIndex); targetChild.setVisibility(View.VISIBLE); + targetChild.setAlpha(0); AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1)); final int count = mContainerView.getChildCount(); @@ -581,7 +546,7 @@ public class ActionBarImpl extends ActionBar { set.addListener(mAfterAnimation[viewIndex]); - mCurrentAnim = set; + mCurrentModeAnim = set; set.start(); return set.getDuration(); } @@ -636,6 +601,10 @@ public class ActionBarImpl extends ActionBar { mLowerContextView.setVisibility(View.GONE); } mActionMode = null; + + if (mWasHiddenBeforeMode) { + hide(); + } } @Override @@ -889,23 +858,24 @@ public class ActionBarImpl extends ActionBar { return mTabs.get(index); } - /** - * This fragment is added when we're keeping a back stack in a tab switch - * transaction. We use it to change the selected tab in the action bar view - * when we back out. - */ - private class SwitchSelectedTabViewFragment extends Fragment { - private int mSelectedTabIndex; - public SwitchSelectedTabViewFragment(int oldSelectedTab) { - mSelectedTabIndex = oldSelectedTab; - } + @Override + public void setIcon(int resId) { + mActionView.setIcon(mContext.getResources().getDrawable(resId)); + } - @Override - public void onDetach() { - if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) { - mActionView.setTabSelected(mSelectedTabIndex); - } - } + @Override + public void setIcon(Drawable icon) { + mActionView.setIcon(icon); + } + + @Override + public void setLogo(int resId) { + mActionView.setLogo(mContext.getResources().getDrawable(resId)); + } + + @Override + public void setLogo(Drawable logo) { + mActionView.setLogo(logo); } } diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl index aee1626..dd22e25 100755 --- a/core/java/com/android/internal/app/IMediaContainerService.aidl +++ b/core/java/com/android/internal/app/IMediaContainerService.aidl @@ -27,8 +27,9 @@ interface IMediaContainerService { String key, String resFileName); boolean copyResource(in Uri packageURI, in ParcelFileDescriptor outStream); - PackageInfoLite getMinimalPackageInfo(in Uri fileUri, int flags); - boolean checkFreeStorage(boolean external, in Uri fileUri); + PackageInfoLite getMinimalPackageInfo(in Uri fileUri, in int flags, in long threshold); + boolean checkInternalFreeStorage(in Uri fileUri, in long threshold); + boolean checkExternalFreeStorage(in Uri fileUri); ObbInfo getObbInfo(in String filename); long calculateDirectorySize(in String directory); } diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index d6c43f9..b57046c 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -56,18 +56,13 @@ public class PackageHelper { return null; } - public static String createSdDir(long sizeBytes, String cid, + public static String createSdDir(int sizeMb, String cid, String sdEncKey, int uid) { // Create mount point via MountService IMountService mountService = getMountService(); - int sizeMb = (int) (sizeBytes >> 20); - if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) { - sizeMb++; - } - // Add buffer size - sizeMb++; + if (localLOGV) - Log.i(TAG, "Size of container " + sizeMb + " MB " + sizeBytes + " bytes"); + Log.i(TAG, "Size of container " + sizeMb + " MB"); try { int rc = mountService.createSecureContainer( diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java index 8c256e0..268a9d4 100644 --- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java +++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java @@ -20,7 +20,8 @@ import android.content.pm.PackageInfo; import android.os.Build; import android.os.SystemProperties; import android.util.Log; -import dalvik.system.SamplingProfiler; +import dalvik.system.profiler.AsciiHprofWriter; +import dalvik.system.profiler.SamplingProfiler; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -162,7 +163,7 @@ public class SamplingProfilerIntegration { try { out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path))); generateSnapshotHeader(name, packageInfo, out); - new SamplingProfiler.AsciiHprofWriter(INSTANCE.getHprofData(), out).write(); + new AsciiHprofWriter(INSTANCE.getHprofData(), out).write(); if (out.checkError()) { throw new IOException(); } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index dea53bf..32ddc22 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -31,7 +31,6 @@ import android.util.Log; import dalvik.system.VMRuntime; import dalvik.system.Zygote; -import dalvik.system.SamplingProfiler; import java.io.BufferedReader; import java.io.FileDescriptor; @@ -99,25 +98,6 @@ public class ZygoteInit { private static final boolean PRELOAD_RESOURCES = true; /** - * List of methods we "warm up" in the register map cache. These were - * chosen because they appeared on the stack in GCs in multiple - * applications. - * - * This is in a VM-ready format, to minimize string processing. If a - * class is not already loaded, or a method is not found, the entry - * will be skipped. - * - * This doesn't really merit a separately-generated input file at this - * time. The list is fairly short, and the consequences of failure - * are minor. - */ - private static final String[] REGISTER_MAP_METHODS = { - // (currently not doing any) - //"Landroid/app/Activity;.setContentView:(I)V", - }; - - - /** * Invokes a static "main(argv[]) method on class "className". * Converts various failing exceptions into RuntimeExceptions, with * the assumption that they will then cause the VM instance to exit. @@ -338,45 +318,6 @@ public class ZygoteInit { } /** - * Pre-caches register maps for methods that are commonly used. - */ - private static void cacheRegisterMaps() { - String failed = null; - int failure; - long startTime = System.nanoTime(); - - failure = 0; - - for (int i = 0; i < REGISTER_MAP_METHODS.length; i++) { - String str = REGISTER_MAP_METHODS[i]; - - if (!Debug.cacheRegisterMap(str)) { - if (failed == null) - failed = str; - failure++; - } - } - - long delta = System.nanoTime() - startTime; - - if (failure == REGISTER_MAP_METHODS.length) { - if (REGISTER_MAP_METHODS.length > 0) { - Log.i(TAG, - "Register map caching failed (precise GC not enabled?)"); - } - return; - } - - Log.i(TAG, "Register map cache: found " + - (REGISTER_MAP_METHODS.length - failure) + " of " + - REGISTER_MAP_METHODS.length + " methods in " + - (delta / 1000000L) + "ms"); - if (failure > 0) { - Log.i(TAG, " First failure: " + failed); - } - } - - /** * Load in commonly used resources, so they can be shared across * processes. * @@ -564,7 +505,6 @@ public class ZygoteInit { EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preloadClasses(); - //cacheRegisterMaps(); preloadResources(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java index 101dd91..4d656c0 100644 --- a/core/java/com/android/internal/util/AsyncChannel.java +++ b/core/java/com/android/internal/util/AsyncChannel.java @@ -135,6 +135,8 @@ public class AsyncChannel { * channel is forcibly disconnected by the system or as a reply to CMD_CHANNEL_DISCONNECT. * * msg.arg1 == 0 : STATUS_SUCCESSFUL + * 1 : STATUS_BINDING_UNSUCCESSFUL + * 2 : STATUS_SEND_UNSUCCESSFUL * : All other values signify failure and the channel state is indeterminate * msg.obj == the AsyncChannel * msg.replyTo = messenger disconnecting or null if it was never connected. @@ -147,6 +149,9 @@ public class AsyncChannel { /** Error attempting to bind on a connect */ public static final int STATUS_BINDING_UNSUCCESSFUL = 1; + /** Error attempting to send a message */ + public static final int STATUS_SEND_UNSUCCESSFUL = 2; + /** Service connection */ private AsyncChannelConnection mConnection; @@ -345,11 +350,7 @@ public class AsyncChannel { mSrcContext.unbindService(mConnection); } if (mSrcHandler != null) { - Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED); - msg.arg1 = STATUS_SUCCESSFUL; - msg.obj = this; - msg.replyTo = mDstMessenger; - mSrcHandler.sendMessage(msg); + replyDisconnected(STATUS_SUCCESSFUL); } } @@ -363,7 +364,7 @@ public class AsyncChannel { try { mDstMessenger.send(msg); } catch (RemoteException e) { - log("TODO: handle sendMessage RemoteException" + e); + replyDisconnected(STATUS_SEND_UNSUCCESSFUL); } } @@ -712,6 +713,7 @@ public class AsyncChannel { /** * Reply to the src handler that we're half connected. + * see: CMD_CHANNEL_HALF_CONNECTED for message contents * * @param status to be stored in msg.arg1 */ @@ -724,6 +726,21 @@ public class AsyncChannel { } /** + * Reply to the src handler that we are disconnected + * see: CMD_CHANNEL_DISCONNECTED for message contents + * + * @param status to be stored in msg.arg1 + */ + private void replyDisconnected(int status) { + Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED); + msg.arg1 = status; + msg.obj = this; + msg.replyTo = mDstMessenger; + mSrcHandler.sendMessage(msg); + } + + + /** * ServiceConnection to receive call backs. */ class AsyncChannelConnection implements ServiceConnection { @@ -736,11 +753,7 @@ public class AsyncChannel { } public void onServiceDisconnected(ComponentName className) { - Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED); - msg.arg1 = STATUS_SUCCESSFUL; - msg.obj = AsyncChannel.this; - msg.replyTo = mDstMessenger; - mSrcHandler.sendMessage(msg); + replyDisconnected(STATUS_SUCCESSFUL); } } diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java index b5df812..c792d78 100644 --- a/core/java/com/android/internal/view/IInputConnectionWrapper.java +++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java @@ -174,7 +174,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub { public void performPrivateCommand(String action, Bundle data) { dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data)); } - + void dispatchMessage(Message msg) { // If we are calling this from the main thread, then we can call // right through. Otherwise, we need to send the message to the diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl index e00dd4e..719a24f 100644 --- a/core/java/com/android/internal/view/IInputContext.aidl +++ b/core/java/com/android/internal/view/IInputContext.aidl @@ -72,4 +72,5 @@ import com.android.internal.view.IInputContextCallback; void setComposingRegion(int start, int end); void getSelectedText(int flags, int seq, IInputContextCallback callback); + } diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java index b13118a..a235d9a 100644 --- a/core/java/com/android/internal/view/InputConnectionWrapper.java +++ b/core/java/com/android/internal/view/InputConnectionWrapper.java @@ -251,7 +251,7 @@ public class InputConnectionWrapper implements InputConnection { } return value; } - + public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { ExtractedText value = null; try { diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java index 3325df6..ca1aa0b 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java @@ -56,6 +56,7 @@ public class ActionMenuItemView extends LinearLayout mTextButton = (Button) findViewById(com.android.internal.R.id.textButton); mImageButton.setOnClickListener(this); mTextButton.setOnClickListener(this); + setOnClickListener(this); } public MenuItemImpl getItemData() { diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 81d02ee..2d9a9f2 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -416,6 +416,21 @@ public class ActionBarView extends ViewGroup { } } + public void setIcon(Drawable icon) { + mIcon = icon; + if (icon != null && + ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null)) { + mIconView.setImageDrawable(icon); + } + } + + public void setLogo(Drawable logo) { + mLogo = logo; + if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) { + mIconView.setImageDrawable(logo); + } + } + public void setNavigationMode(int mode) { final int oldMode = mNavigationMode; if (mode != oldMode) { diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java index 9f9f020..5bf6026 100644 --- a/core/java/com/android/internal/widget/EditableInputConnection.java +++ b/core/java/com/android/internal/widget/EditableInputConnection.java @@ -17,8 +17,10 @@ package com.android.internal.widget; import android.os.Bundle; +import android.os.IBinder; import android.text.Editable; import android.text.method.KeyListener; +import android.text.style.CorrectionSpan; import android.util.Log; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.CompletionInfo; diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl index 5857acb..18076c4 100644 --- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl +++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl @@ -22,7 +22,7 @@ import android.widget.RemoteViews; /** {@hide} */ interface IRemoteViewsFactory { void onDataSetChanged(); - void onDestroy(in Intent intent); + oneway void onDestroy(in Intent intent); int getCount(); RemoteViews getViewAt(int position); RemoteViews getLoadingView(); diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index 076a1cb..c34cb9e 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -357,6 +357,12 @@ public class PointerLocationView extends View { case MotionEvent.ACTION_HOVER_MOVE: prefix = "HOVER MOVE"; break; + case MotionEvent.ACTION_HOVER_ENTER: + prefix = "HOVER ENTER"; + break; + case MotionEvent.ACTION_HOVER_EXIT: + prefix = "HOVER EXIT"; + break; case MotionEvent.ACTION_SCROLL: prefix = "SCROLL"; break; diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 1c4dc29..54b7fbb 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -54,6 +54,7 @@ LOCAL_SRC_FILES:= \ android_view_KeyCharacterMap.cpp \ android_view_GLES20Canvas.cpp \ android_view_MotionEvent.cpp \ + android_view_VelocityTracker.cpp \ android_text_AndroidCharacter.cpp \ android_text_AndroidBidi.cpp \ android_os_Debug.cpp \ @@ -92,6 +93,7 @@ LOCAL_SRC_FILES:= \ android/graphics/DrawFilter.cpp \ android/graphics/CreateJavaOutputStreamAdaptor.cpp \ android/graphics/Graphics.cpp \ + android/graphics/HarfbuzzSkia.cpp \ android/graphics/Interpolator.cpp \ android/graphics/LayerRasterizer.cpp \ android/graphics/MaskFilter.cpp \ @@ -99,6 +101,7 @@ LOCAL_SRC_FILES:= \ android/graphics/Movie.cpp \ android/graphics/NinePatch.cpp \ android/graphics/NinePatchImpl.cpp \ + android/graphics/NinePatchPeeker.cpp \ android/graphics/Paint.cpp \ android/graphics/Path.cpp \ android/graphics/PathMeasure.cpp \ @@ -112,6 +115,7 @@ LOCAL_SRC_FILES:= \ android/graphics/Shader.cpp \ android/graphics/SurfaceTexture.cpp \ android/graphics/TextLayout.cpp \ + android/graphics/TextLayoutCache.cpp \ android/graphics/Typeface.cpp \ android/graphics/Utils.cpp \ android/graphics/Xfermode.cpp \ @@ -171,6 +175,7 @@ LOCAL_C_INCLUDES += \ external/icu4c/i18n \ external/icu4c/common \ external/jpeg \ + external/harfbuzz/src \ frameworks/opt/emoji LOCAL_SHARED_LIBRARIES := \ @@ -182,7 +187,6 @@ LOCAL_SHARED_LIBRARIES := \ libnetutils \ libui \ libgui \ - libsurfaceflinger_client \ libcamera_client \ libskia \ libsqlite \ @@ -203,6 +207,7 @@ LOCAL_SHARED_LIBRARIES := \ libjpeg \ libnfc_ndef \ libusbhost \ + libharfbuzz \ ifeq ($(USE_OPENGL_RENDERER),true) LOCAL_SHARED_LIBRARIES += libhwui diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 0e071a4..e4eb692 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -170,6 +170,7 @@ extern int register_android_view_InputChannel(JNIEnv* env); extern int register_android_view_InputQueue(JNIEnv* env); extern int register_android_view_KeyEvent(JNIEnv* env); extern int register_android_view_MotionEvent(JNIEnv* env); +extern int register_android_view_VelocityTracker(JNIEnv* env); extern int register_android_content_res_ObbScanner(JNIEnv* env); extern int register_android_content_res_Configuration(JNIEnv* env); extern int register_android_animation_PropertyValuesHolder(JNIEnv *env); @@ -1302,6 +1303,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_InputQueue), REG_JNI(register_android_view_KeyEvent), REG_JNI(register_android_view_MotionEvent), + REG_JNI(register_android_view_VelocityTracker), REG_JNI(register_android_content_res_ObbScanner), REG_JNI(register_android_content_res_Configuration), diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 8064836..05a46a8 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -100,6 +100,8 @@ bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, dst = (char*)dst + dstBitmap.rowBytes();
}
+ dstBitmap.notifyPixelsChanged();
+
env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
JNI_ABORT);
return true;
@@ -524,6 +526,7 @@ static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, }
proc(bitmap->getAddr(x, y), &color, 1, x, y);
+ bitmap->notifyPixelsChanged();
}
static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 491a388..1034fbd 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -1,6 +1,7 @@ #define LOG_TAG "BitmapFactory" #include "BitmapFactory.h" +#include "NinePatchPeeker.h" #include "SkImageDecoder.h" #include "SkImageRef_ashmem.h" #include "SkImageRef_GlobalPool.h" @@ -47,65 +48,6 @@ static jfieldID gFileDescriptor_descriptor; using namespace android; -class NinePatchPeeker : public SkImageDecoder::Peeker { - SkImageDecoder* fHost; -public: - NinePatchPeeker(SkImageDecoder* host) { - // the host lives longer than we do, so a raw ptr is safe - fHost = host; - fPatchIsValid = false; - } - - ~NinePatchPeeker() { - if (fPatchIsValid) { - free(fPatch); - } - } - - bool fPatchIsValid; - Res_png_9patch* fPatch; - - virtual bool peek(const char tag[], const void* data, size_t length) { - if (strcmp("npTc", tag) == 0 && length >= sizeof(Res_png_9patch)) { - Res_png_9patch* patch = (Res_png_9patch*) data; - size_t patchSize = patch->serializedSize(); - assert(length == patchSize); - // You have to copy the data because it is owned by the png reader - Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize); - memcpy(patchNew, patch, patchSize); - // this relies on deserialization being done in place - Res_png_9patch::deserialize(patchNew); - patchNew->fileToDevice(); - if (fPatchIsValid) { - free(fPatch); - } - fPatch = patchNew; - //printf("9patch: (%d,%d)-(%d,%d)\n", - // fPatch.sizeLeft, fPatch.sizeTop, - // fPatch.sizeRight, fPatch.sizeBottom); - fPatchIsValid = true; - - // now update our host to force index or 32bit config - // 'cause we don't want 565 predithered, since as a 9patch, we know - // we will be stretched, and therefore we want to dither afterwards. - static const SkBitmap::Config gNo565Pref[] = { - SkBitmap::kIndex8_Config, - SkBitmap::kIndex8_Config, - SkBitmap::kARGB_8888_Config, - SkBitmap::kARGB_8888_Config, - SkBitmap::kARGB_8888_Config, - SkBitmap::kARGB_8888_Config, - }; - fHost->setPrefConfigTable(gNo565Pref); - } else { - fPatch = NULL; - } - return true; // keep on decoding - } -}; - -/////////////////////////////////////////////////////////////////////////////// - static inline int32_t validOrNeg1(bool isValid, int32_t value) { // return isValid ? value : -1; SkASSERT((int)isValid == 0 || (int)isValid == 1); diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 0cdb357..b4ad9e9 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -755,6 +755,27 @@ public: env->ReleaseStringChars(text, textArray); } + static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas, + jcharArray glyphs, int index, int count, + jfloat x, jfloat y, int flags, SkPaint* paint) { + jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL); + + // TODO: need to suppress this code after the GL renderer is modified for not + // copying the paint + + // Save old text encoding + SkPaint::TextEncoding oldEncoding = paint->getTextEncoding(); + // Define Glyph encoding + paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); + + TextLayout::drawText(paint, glyphArray + index, count, flags, x, y, canvas); + + // Get back old encoding + paint->setTextEncoding(oldEncoding); + + env->ReleaseCharArrayElements(glyphs, glyphArray, JNI_ABORT); + } + static void drawTextRun___CIIIIFFIPaint( JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, int contextIndex, int contextCount, @@ -946,6 +967,8 @@ static JNINativeMethod gCanvasMethods[] = { (void*) SkCanvasGlue::drawText___CIIFFIPaint}, {"native_drawText","(ILjava/lang/String;IIFFII)V", (void*) SkCanvasGlue::drawText__StringIIFFIPaint}, + {"native_drawGlyphs","(I[CIIFFII)V", + (void*) SkCanvasGlue::drawGlyphs___CIIFFIPaint}, {"native_drawTextRun","(I[CIIIIFFII)V", (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint}, {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V", diff --git a/core/jni/android/graphics/HarfbuzzSkia.cpp b/core/jni/android/graphics/HarfbuzzSkia.cpp new file mode 100644 index 0000000..58fb32b --- /dev/null +++ b/core/jni/android/graphics/HarfbuzzSkia.cpp @@ -0,0 +1,239 @@ +/* + * Copyright 2011, The Android Open Source Project + * Copyright 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "HarfbuzzSkia.h" + +#include "SkFontHost.h" + +#include "SkPaint.h" +#include "SkPath.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkTypeface.h" + +extern "C" { +#include "harfbuzz-shaper.h" +} + +// This file implements the callbacks which Harfbuzz requires by using Skia +// calls. See the Harfbuzz source for references about what these callbacks do. + +namespace android { + +static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value) +{ + // HB_Fixed is a 26.6 fixed point format. + return value * 64; +} + +static void setupPaintWithFontData(SkPaint* paint, FontData* data) { + paint->setAntiAlias(true); + paint->setSubpixelText(true); + paint->setHinting(SkPaint::kSlight_Hinting); + paint->setTextSize(SkFloatToScalar(data->textSize)); + paint->setTypeface(data->typeFace); + paint->setFakeBoldText(data->fakeBold); + paint->setTextSkewX(data->fakeItalic ? -SK_Scalar1/4 : 0); +} + +static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, + HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL) +{ + FontData* data = reinterpret_cast<FontData*>(hbFont->userData); + SkPaint paint; + setupPaintWithFontData(&paint, data); + + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), + reinterpret_cast<uint16_t*>(glyphs)); + + // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our + // |glyphs| array needs to be converted. + for (int i = numGlyphs - 1; i >= 0; --i) { + uint16_t value; + // We use a memcpy to avoid breaking strict aliasing rules. + memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(value)); + glyphs[i] = value; + } + + *glyphsSize = numGlyphs; + return 1; +} + +static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, + HB_Fixed* advances, int flags) +{ + FontData* data = reinterpret_cast<FontData*>(hbFont->userData); + SkPaint paint; + setupPaintWithFontData(&paint, data); + + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + + uint16_t* glyphs16 = new uint16_t[numGlyphs]; + if (!glyphs16) + return; + for (unsigned i = 0; i < numGlyphs; ++i) + glyphs16[i] = glyphs[i]; + paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances)); + + // The |advances| values which Skia outputs are SkScalars, which are floats + // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format. + // These two formats are both 32-bits long. + for (unsigned i = 0; i < numGlyphs; ++i) { + float value; + // We use a memcpy to avoid breaking strict aliasing rules. + memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(value)); + advances[i] = SkiaScalarToHarfbuzzFixed(value); + } + delete glyphs16; +} + +static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length) +{ + FontData* data = reinterpret_cast<FontData*>(hbFont->userData); + SkPaint paint; + setupPaintWithFontData(&paint, data); + + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + + uint16_t* glyphs16 = new uint16_t[length]; + int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16); + + bool result = true; + for (int i = 0; i < numGlyphs; ++i) { + if (!glyphs16[i]) { + result = false; + break; + } + } + delete glyphs16; + return result; +} + +static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, + HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints) +{ + FontData* data = reinterpret_cast<FontData*>(hbFont->userData); + SkPaint paint; + setupPaintWithFontData(&paint, data); + + if (flags & HB_ShaperFlag_UseDesignMetrics) + // This is requesting pre-hinted positions. We can't support this. + return HB_Err_Invalid_Argument; + + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + uint16_t glyph16 = glyph; + SkPath path; + paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); + uint32_t numPoints = path.getPoints(0, 0); + if (point >= numPoints) + return HB_Err_Invalid_SubTable; + SkPoint* points = reinterpret_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1))); + if (!points) + return HB_Err_Invalid_SubTable; + // Skia does let us get a single point from the path. + path.getPoints(points, point + 1); + *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX); + *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY); + *resultingNumPoints = numPoints; + delete points; + + return HB_Err_Ok; +} + +static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics) +{ + FontData* data = reinterpret_cast<FontData*>(hbFont->userData); + SkPaint paint; + setupPaintWithFontData(&paint, data); + + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + uint16_t glyph16 = glyph; + SkScalar width; + SkRect bounds; + paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds); + + metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft); + metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop); + metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width()); + metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height()); + + metrics->xOffset = SkiaScalarToHarfbuzzFixed(width); + // We can't actually get the |y| correct because Skia doesn't export + // the vertical advance. However, nor we do ever render vertical text at + // the moment so it's unimportant. + metrics->yOffset = 0; +} + +static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric) +{ + FontData* data = reinterpret_cast<FontData*>(hbFont->userData); + SkPaint paint; + setupPaintWithFontData(&paint, data); + + SkPaint::FontMetrics skiaMetrics; + paint.getFontMetrics(&skiaMetrics); + + switch (metric) { + case HB_FontAscent: + return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent); + // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them. + default: + return 0; + } + return 0; +} + +const HB_FontClass harfbuzzSkiaClass = { + stringToGlyphs, + glyphsToAdvances, + canRender, + getOutlinePoint, + getGlyphMetrics, + getFontMetric, +}; + +HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len) +{ + FontData* data = reinterpret_cast<FontData*>(voidface); + SkTypeface* typeface = data->typeFace; + + const size_t tableSize = SkFontHost::GetTableSize(typeface->uniqueID(), tag); + if (!tableSize) + return HB_Err_Invalid_Argument; + // If Harfbuzz specified a NULL buffer then it's asking for the size of the table. + if (!buffer) { + *len = tableSize; + return HB_Err_Ok; + } + + if (*len < tableSize) + return HB_Err_Invalid_Argument; + SkFontHost::GetTableData(typeface->uniqueID(), tag, 0, tableSize, buffer); + return HB_Err_Ok; +} + +} // namespace android diff --git a/core/jni/android/graphics/HarfbuzzSkia.h b/core/jni/android/graphics/HarfbuzzSkia.h new file mode 100644 index 0000000..d057d76 --- /dev/null +++ b/core/jni/android/graphics/HarfbuzzSkia.h @@ -0,0 +1,48 @@ +/* + * Copyright 2011, The Android Open Source Project + * Copyright 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HarfbuzzSkia_h +#define HarfbuzzSkia_h + +#include "SkTypeface.h" + +extern "C" { +#include "harfbuzz-shaper.h" +} + +namespace android { + typedef struct { + SkTypeface* typeFace; + float textSize; + bool fakeBold; + bool fakeItalic; + } FontData; + + HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len); + extern const HB_FontClass harfbuzzSkiaClass; +} // namespace android + +#endif diff --git a/core/jni/android/graphics/NinePatchPeeker.cpp b/core/jni/android/graphics/NinePatchPeeker.cpp new file mode 100644 index 0000000..365d985 --- /dev/null +++ b/core/jni/android/graphics/NinePatchPeeker.cpp @@ -0,0 +1,59 @@ +/* + * 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 "NinePatchPeeker.h" + +#include "SkBitmap.h" + +using namespace android; + +bool NinePatchPeeker::peek(const char tag[], const void* data, size_t length) { + if (strcmp("npTc", tag) == 0 && length >= sizeof(Res_png_9patch)) { + Res_png_9patch* patch = (Res_png_9patch*) data; + size_t patchSize = patch->serializedSize(); + assert(length == patchSize); + // You have to copy the data because it is owned by the png reader + Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize); + memcpy(patchNew, patch, patchSize); + // this relies on deserialization being done in place + Res_png_9patch::deserialize(patchNew); + patchNew->fileToDevice(); + if (fPatchIsValid) { + free(fPatch); + } + fPatch = patchNew; + //printf("9patch: (%d,%d)-(%d,%d)\n", + // fPatch.sizeLeft, fPatch.sizeTop, + // fPatch.sizeRight, fPatch.sizeBottom); + fPatchIsValid = true; + + // now update our host to force index or 32bit config + // 'cause we don't want 565 predithered, since as a 9patch, we know + // we will be stretched, and therefore we want to dither afterwards. + static const SkBitmap::Config gNo565Pref[] = { + SkBitmap::kIndex8_Config, + SkBitmap::kIndex8_Config, + SkBitmap::kARGB_8888_Config, + SkBitmap::kARGB_8888_Config, + SkBitmap::kARGB_8888_Config, + SkBitmap::kARGB_8888_Config, + }; + fHost->setPrefConfigTable(gNo565Pref); + } else { + fPatch = NULL; + } + return true; // keep on decoding +} diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/core/jni/android/graphics/NinePatchPeeker.h new file mode 100644 index 0000000..8567e23 --- /dev/null +++ b/core/jni/android/graphics/NinePatchPeeker.h @@ -0,0 +1,46 @@ +/* + * 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 NinePatchPeeker_h +#define NinePatchPeeker_h + +#include "SkImageDecoder.h" +#include <utils/ResourceTypes.h> + +using namespace android; + +class NinePatchPeeker : public SkImageDecoder::Peeker { + SkImageDecoder* fHost; +public: + NinePatchPeeker(SkImageDecoder* host) { + // the host lives longer than we do, so a raw ptr is safe + fHost = host; + fPatchIsValid = false; + } + + ~NinePatchPeeker() { + if (fPatchIsValid) { + free(fPatch); + } + } + + bool fPatchIsValid; + Res_png_9patch* fPatch; + + virtual bool peek(const char tag[], const void* data, size_t length); +}; + +#endif // NinePatchPeeker_h diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index e62b034..5c3497f 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -393,13 +393,40 @@ public: return count; } - static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloatArray widths) { + static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, + int start, int end, jfloatArray widths) { const jchar* textArray = env->GetStringChars(text, NULL); int count = dotextwidths(env, paint, textArray + start, end - start, widths); env->ReleaseStringChars(text, textArray); return count; } + static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count, + jint contextCount, jint flags, jcharArray glyphs) { + jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL); + HB_ShaperItem shaperItem; + HB_FontRec font; + FontData fontData; + RunAdvanceDescription::shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, text, + start, count, contextCount, flags); + + int glyphCount = shaperItem.num_glyphs; + for (int i = 0; i < glyphCount; i++) { + glyphsArray[i] = (jchar) shaperItem.glyphs[i]; + } + return glyphCount; + } + + static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint, + jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags, + jcharArray glyphs) { + const jchar* textArray = env->GetStringChars(text, NULL); + int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart, + end - start, contextEnd - contextStart, flags, glyphs); + env->ReleaseStringChars(text, textArray); + return count; + } + static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text, jint start, jint count, jint contextCount, jint flags, jfloatArray advances, jint advancesIndex) { @@ -725,6 +752,8 @@ static JNINativeMethod methods[] = { SkPaintGlue::getTextRunAdvances___CIIIII_FI}, {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F", (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI}, + {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I", + (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C}, {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C}, {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I", (void*) SkPaintGlue::getTextRunCursor__String}, diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h new file mode 100644 index 0000000..2c68fa3 --- /dev/null +++ b/core/jni/android/graphics/RtlProperties.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 ANDROID_RTL_PROPERTIES_H +#define ANDROID_RTL_PROPERTIES_H + +#include <cutils/properties.h> +#include <stdlib.h> + +namespace android { + +/** + * Debug level for app developers. + */ +#define RTL_PROPERTY_DEBUG "rtl.debug_level" + +/** + * Debug levels. Debug levels are used as flags. + */ +enum RtlDebugLevel { + kRtlDebugDisabled = 0, + kRtlDebugMemory = 1, + kRtlDebugCaches = 2, + kRtlDebugAllocations = 3 +}; + +static RtlDebugLevel readRtlDebugLevel() { + char property[PROPERTY_VALUE_MAX]; + if (property_get(RTL_PROPERTY_DEBUG, property, NULL) > 0) { + return (RtlDebugLevel) atoi(property); + } + return kRtlDebugDisabled; +} + +#define RTL_USE_HARFBUZZ 1 + +} // namespace android +#endif // ANDROID_RTL_PROPERTIES_H diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index c4e5878..2f70190 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -171,6 +171,12 @@ static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz, env->ReleaseFloatArrayElements(jmtx, mtx, 0); } +static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz) +{ + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + return surfaceTexture->getTimestamp(); +} + // ---------------------------------------------------------------------------- const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture"; @@ -178,9 +184,10 @@ const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTextur static JNINativeMethod gSurfaceTextureMethods[] = { {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit }, {"nativeInit", "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init }, - {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, + {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix }, + {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp } }; int register_android_graphics_SurfaceTexture(JNIEnv* env) diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp index e957635..f1bb696 100644 --- a/core/jni/android/graphics/TextLayout.cpp +++ b/core/jni/android/graphics/TextLayout.cpp @@ -15,6 +15,7 @@ */ #include "TextLayout.h" +#include "TextLayoutCache.h" #include <android_runtime/AndroidRuntime.h> @@ -23,10 +24,12 @@ #include "unicode/ushape.h" #include <utils/Log.h> -// Log debug messages from RTL related allocations -#define DEBUG_RTL_ALLOCATIONS 0 - namespace android { + +#if USE_TEXT_LAYOUT_CACHE +TextLayoutCache TextLayout::mCache; +#endif + // Returns true if we might need layout. If bidiFlags force LTR, assume no layout, if // bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text // looking for a character >= the first RTL character in unicode and assume we do if @@ -60,14 +63,10 @@ bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) { * @return the length of the shaped text, or -1 if error */ int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount, - jchar* shaped, UErrorCode &status) { + jchar* shaped, UErrorCode& status) { SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount); jchar* buffer = tempBuffer.get(); -#if DEBUG_RTL_ALLOCATIONS - LOGD("TextLayout::shapeRtlText - allocated buffer with size: %d", contextCount); -#endif - // Use fixed length since we need to keep start and count valid u_shapeArabic(context, contextCount, buffer, contextCount, U_SHAPE_LENGTH_FIXED_SPACES_NEAR | @@ -105,8 +104,8 @@ int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsi * @flags line bidi flags * @return the length of the reordered, shaped line, or -1 if error */ -jint TextLayout::layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer, - UErrorCode &status) { +jint TextLayout::layoutLine(const jchar* text, jint len, jint flags, int& dir, jchar* buffer, + UErrorCode& status) { static const int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING | UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE; @@ -156,7 +155,7 @@ jint TextLayout::layoutLine(const jchar* text, jint len, jint flags, int &dir, j return result; } -bool TextLayout::prepareText(SkPaint *paint, const jchar* text, jsize len, jint bidiFlags, +bool TextLayout::prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags, const jchar** outText, int32_t* outBytes, jchar** outBuffer) { const jchar *workText = text; jchar *buffer = NULL; @@ -166,11 +165,6 @@ bool TextLayout::prepareText(SkPaint *paint, const jchar* text, jsize len, jint if (!buffer) { return false; } - -#if DEBUG_RTL_ALLOCATIONS - LOGD("TextLayout::prepareText - allocated buffer with size: %d", len); -#endif - UErrorCode status = U_ZERO_ERROR; len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir if (!U_SUCCESS(status)) { @@ -178,7 +172,6 @@ bool TextLayout::prepareText(SkPaint *paint, const jchar* text, jsize len, jint free(buffer); return false; // can't render } - workText = buffer; // use the shaped text } @@ -262,74 +255,24 @@ void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars, } } -void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint start, +void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start, jint count, jint contextCount, jint dirFlags, - jfloat *resultAdvances, jfloat &resultTotalAdvance) { - resultTotalAdvance = 0; - - SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount); - jchar* buffer = tempBuffer.get(); - -#if DEBUG_RTL_ALLOCATIONS - LOGD("TextLayout::getTextRunAdvances - allocated buffer with size: %d", contextCount); + jfloat* resultAdvances, jfloat& resultTotalAdvance) { +#if USE_TEXT_LAYOUT_CACHE + // Return advances from the cache. Compute them if needed + mCache.getRunAdvances(paint, chars, start, count, contextCount, + dirFlags, resultAdvances, &resultTotalAdvance); +#else + // Compute advances and return them + RunAdvanceDescription::computeAdvances(paint, chars, start, count, contextCount, dirFlags, + resultAdvances, &resultTotalAdvance); #endif - - SkScalar* scalarArray = (SkScalar*)resultAdvances; - - // this is where we'd call harfbuzz - // for now we just use ushape.c - - int widths; - const jchar* text; - if (dirFlags & 0x1) { // rtl, call arabic shaping in case - UErrorCode status = U_ZERO_ERROR; - // Use fixed length since we need to keep start and count valid - u_shapeArabic(chars, contextCount, buffer, contextCount, - U_SHAPE_LENGTH_FIXED_SPACES_NEAR | - U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE | - U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); - // we shouldn't fail unless there's an out of memory condition, - // in which case we're hosed anyway - for (int i = start, e = i + count; i < e; ++i) { - if (buffer[i] == UNICODE_NOT_A_CHAR) { - buffer[i] = UNICODE_ZWSP; // zero-width-space for skia - } - } - text = buffer + start; - widths = paint->getTextWidths(text, count << 1, scalarArray); - } else { - text = chars + start; - widths = paint->getTextWidths(text, count << 1, scalarArray); - } - - if (widths < count) { - // Skia operates on code points, not code units, so surrogate pairs return only - // one value. Expand the result so we have one value per UTF-16 code unit. - - // Note, skia's getTextWidth gets confused if it encounters a surrogate pair, - // leaving the remaining widths zero. Not nice. - for (int i = 0, p = 0; i < widths; ++i) { - resultTotalAdvance += resultAdvances[p++] = SkScalarToFloat(scalarArray[i]); - if (p < count && - text[p] >= UNICODE_FIRST_LOW_SURROGATE && - text[p] < UNICODE_FIRST_PRIVATE_USE && - text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE && - text[p-1] < UNICODE_FIRST_LOW_SURROGATE) { - resultAdvances[p++] = 0; - } - } - } else { - for (int i = 0; i < count; i++) { - resultTotalAdvance += resultAdvances[i] = SkScalarToFloat(scalarArray[i]); - } - } } // Draws a paragraph of text on a single line, running bidi and shaping void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len, int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas) { - handleText(paint, text, len, bidiFlags, x, y, canvas, NULL); } @@ -353,10 +296,6 @@ void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count, SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(count); -#if DEBUG_RTL_ALLOCATIONS - LOGD("TextLayout::drawTextOnPath - allocated buffer with size: %d", count); -#endif - int dir = kDirection_LTR; UErrorCode status = U_ZERO_ERROR; count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status); diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h index c98f745..a950d13 100644 --- a/core/jni/android/graphics/TextLayout.h +++ b/core/jni/android/graphics/TextLayout.h @@ -20,6 +20,8 @@ #include "SkPaint.h" #include "unicode/utypes.h" +#include "TextLayoutCache.h" + namespace android { #define UNICODE_NOT_A_CHAR 0xffff @@ -34,6 +36,11 @@ namespace android { */ #define CHAR_BUFFER_SIZE 80 +/** + * Turn on for using the Cache + */ +#define USE_TEXT_LAYOUT_CACHE 1 + class TextLayout { public: @@ -62,22 +69,23 @@ public: jint start, jint count, jint contextCount, int dirFlags, jfloat x, jfloat y, SkCanvas* canvas); - static void getTextRunAdvances(SkPaint *paint, const jchar *chars, jint start, + static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start, jint count, jint contextCount, jint dirFlags, - jfloat *resultAdvances, jfloat &resultTotalAdvance); + jfloat* resultAdvances, jfloat& resultTotalAdvance); static void drawText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags, jfloat x, jfloat y, SkCanvas* canvas); - static void getTextPath(SkPaint *paint, const jchar *text, jsize len, - jint bidiFlags, jfloat x, jfloat y, SkPath *path); + static void getTextPath(SkPaint* paint, const jchar* text, jsize len, + jint bidiFlags, jfloat x, jfloat y, SkPath* path); static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len, int bidiFlags, jfloat hOffset, jfloat vOffset, SkPath* path, SkCanvas* canvas); - static bool prepareText(SkPaint *paint, const jchar* text, jsize len, jint bidiFlags, + static bool prepareText(SkPaint* paint, const jchar* text, jsize len, jint bidiFlags, const jchar** outText, int32_t* outBytes, jchar** outBuffer); + static bool prepareRtlTextRun(const jchar* context, jsize start, jsize& count, jsize contextCount, jchar* shaped); @@ -85,11 +93,15 @@ public: private: static bool needsLayout(const jchar* text, jint len, jint bidiFlags); static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount, - jchar* shaped, UErrorCode &status); + jchar* shaped, UErrorCode& status); static jint layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer, UErrorCode &status); - static void handleText(SkPaint *paint, const jchar* text, jsize len, - int bidiFlags, jfloat x, jfloat y,SkCanvas *canvas, SkPath *path); + static void handleText(SkPaint* paint, const jchar* text, jsize len, + int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas, SkPath* path); + +#if USE_TEXT_LAYOUT_CACHE + static TextLayoutCache mCache; +#endif }; } diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp new file mode 100644 index 0000000..a7265be --- /dev/null +++ b/core/jni/android/graphics/TextLayoutCache.cpp @@ -0,0 +1,218 @@ +/* + * 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 "TextLayoutCache.h" + +namespace android { + +TextLayoutCache::TextLayoutCache(): + mCache(GenerationCache<TextLayoutCacheKey, RunAdvanceDescription*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)), + mCacheHitCount(0), mNanosecondsSaved(0) { + init(); +} + +TextLayoutCache::TextLayoutCache(uint32_t max): + mCache(GenerationCache<TextLayoutCacheKey, RunAdvanceDescription*>::kUnlimitedCapacity), + mSize(0), mMaxSize(max), + mCacheHitCount(0), mNanosecondsSaved(0) { + init(); +} + +TextLayoutCache::~TextLayoutCache() { + mCache.clear(); +} + +void TextLayoutCache::init() { + mCache.setOnEntryRemovedListener(this); + + mDebugLevel = readRtlDebugLevel(); + mDebugEnabled = mDebugLevel & kRtlDebugCaches; + LOGD("Using TextLayoutCache debug level: %d - Debug Enabled: %d", mDebugLevel, mDebugEnabled); + + mCacheStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + if (mDebugEnabled) { + LOGD("TextLayoutCache start time: %lld", mCacheStartTime); + } + mInitialized = true; + + if (mDebugEnabled) { +#if RTL_USE_HARFBUZZ + LOGD("TextLayoutCache is using HARFBUZZ"); +#else + LOGD("TextLayoutCache is using ICU"); +#endif + } + + if (mDebugEnabled) { + LOGD("TextLayoutCache initialization is done"); + } +} + +/* + * Size management + */ + +uint32_t TextLayoutCache::getSize() { + return mSize; +} + +uint32_t TextLayoutCache::getMaxSize() { + return mMaxSize; +} + +void TextLayoutCache::setMaxSize(uint32_t maxSize) { + mMaxSize = maxSize; + removeOldests(); +} + +void TextLayoutCache::removeOldests() { + while (mSize > mMaxSize) { + mCache.removeOldest(); + } +} + +/** + * Callbacks + */ +void TextLayoutCache::operator()(TextLayoutCacheKey& text, RunAdvanceDescription*& desc) { + if (desc) { + size_t totalSizeToDelete = text.getSize() + desc->getSize(); + mSize -= totalSizeToDelete; + if (mDebugEnabled) { + LOGD("RunAdvance description deleted, size = %d", totalSizeToDelete); + } + delete desc; + } +} + +/* + * Cache clearing + */ +void TextLayoutCache::clear() { + mCache.clear(); +} + +/* + * Caching + */ +void TextLayoutCache::getRunAdvances(SkPaint* paint, const jchar* text, + jint start, jint count, jint contextCount, jint dirFlags, + jfloat* outAdvances, jfloat* outTotalAdvance) { + + AutoMutex _l(mLock); + + nsecs_t startTime = 0; + if (mDebugEnabled) { + startTime = systemTime(SYSTEM_TIME_MONOTONIC); + } + + TextLayoutCacheKey entry(paint, text, start, count, contextCount, dirFlags); + + // Get entry for cache if possible + RunAdvanceDescription* desc = mCache.get(entry); + + // Value not found for the entry, we need to add a new value in the cache + if (!desc) { + desc = new RunAdvanceDescription(); + + // Compute advances and store them + desc->computeAdvances(paint, text, start, count, contextCount, dirFlags); + desc->copyResult(outAdvances, outTotalAdvance); + + // Don't bother to add in the cache if the entry is too big + size_t size = entry.getSize() + desc->getSize(); + if (size <= mMaxSize) { + // Cleanup to make some room if needed + if (mSize + size > mMaxSize) { + if (mDebugEnabled) { + LOGD("TextLayoutCache: need to clean some entries " + "for making some room for a new entry"); + } + while (mSize + size > mMaxSize) { + // This will call the callback + mCache.removeOldest(); + } + } + + // Update current cache size + mSize += size; + + // Copy the text when we insert the new entry + entry.internalTextCopy(); + mCache.put(entry, desc); + + if (mDebugEnabled) { + // Update timing information for statistics. + desc->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime); + + LOGD("CACHE MISS: Added entry for text='%s' with start=%d, count=%d, " + "contextCount=%d, entry size %d bytes, remaining space %d bytes" + " - Compute time in nanos: %d", + String8(text, contextCount).string(), start, count, contextCount, + size, mMaxSize - mSize, desc->getElapsedTime()); + } + } else { + if (mDebugEnabled) { + LOGD("CACHE MISS: Calculated but not storing entry because it is too big " + "for text='%s' with start=%d, count=%d, contextCount=%d, " + "entry size %d bytes, remaining space %d bytes" + " - Compute time in nanos: %d", + String8(text, contextCount).string(), start, count, contextCount, + size, mMaxSize - mSize, desc->getElapsedTime()); + } + delete desc; + } + } else { + // This is a cache hit, just copy the pre-computed results + desc->copyResult(outAdvances, outTotalAdvance); + if (mDebugEnabled) { + nsecs_t elapsedTimeThruCacheGet = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; + mNanosecondsSaved += (desc->getElapsedTime() - elapsedTimeThruCacheGet); + ++mCacheHitCount; + + if (desc->getElapsedTime() > 0) { + float deltaPercent = 100 * ((desc->getElapsedTime() - elapsedTimeThruCacheGet) + / ((float)desc->getElapsedTime())); + LOGD("CACHE HIT #%d for text='%s' with start=%d, count=%d, contextCount=%d " + "- Compute time in nanos: %d - " + "Cache get time in nanos: %lld - Gain in percent: %2.2f", + mCacheHitCount, String8(text, contextCount).string(), start, count, + contextCount, + desc->getElapsedTime(), elapsedTimeThruCacheGet, deltaPercent); + } + if (mCacheHitCount % DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL == 0) { + dumpCacheStats(); + } + } + } +} + +void TextLayoutCache::dumpCacheStats() { + float remainingPercent = 100 * ((mMaxSize - mSize) / ((float)mMaxSize)); + float timeRunningInSec = (systemTime(SYSTEM_TIME_MONOTONIC) - mCacheStartTime) / 1000000000; + LOGD("------------------------------------------------"); + LOGD("TextLayoutCache stats"); + LOGD("------------------------------------------------"); + LOGD("running : %.0f seconds", timeRunningInSec); + LOGD("size : %d bytes", mMaxSize); + LOGD("remaining : %d bytes or %2.2f percent", mMaxSize - mSize, remainingPercent); + LOGD("hits : %d", mCacheHitCount); + LOGD("saved : %lld milliseconds", mNanosecondsSaved / 1000000); + LOGD("------------------------------------------------"); +} + +} // namespace android diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h new file mode 100644 index 0000000..925bb7c --- /dev/null +++ b/core/jni/android/graphics/TextLayoutCache.h @@ -0,0 +1,470 @@ +/* + * 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_TEXT_LAYOUT_CACHE_H +#define ANDROID_TEXT_LAYOUT_CACHE_H + +#include "RtlProperties.h" + +#include "stddef.h" +#include <utils/threads.h> +#include <utils/String16.h> +#include "utils/GenerationCache.h" +#include "utils/Compare.h" + +#include "SkPaint.h" +#include "SkTemplates.h" + +#include "unicode/ubidi.h" +#include "unicode/ushape.h" +#include "HarfbuzzSkia.h" +#include "harfbuzz-shaper.h" + +#include <android_runtime/AndroidRuntime.h> + +#define UNICODE_NOT_A_CHAR 0xffff +#define UNICODE_ZWSP 0x200b +#define UNICODE_FIRST_LOW_SURROGATE 0xdc00 +#define UNICODE_FIRST_HIGH_SURROGATE 0xd800 +#define UNICODE_FIRST_PRIVATE_USE 0xe000 +#define UNICODE_FIRST_RTL_CHAR 0x0590 + +// Temporary buffer size +#define CHAR_BUFFER_SIZE 80 + +// Converts a number of mega-bytes into bytes +#define MB(s) s * 1024 * 1024 + +// Define the default cache size in Mb +#define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.125f + +// Define the interval in number of cache hits between two statistics dump +#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100 + +// Define if we want to have Advances debug values +#define DEBUG_ADVANCES 0 + +namespace android { + +// Harfbuzz uses 26.6 fixed point values for pixel offsets +#define HB_FIXED_TO_FLOAT(v) (((float) v) * (1.0 / 64)) + +/** + * TextLayoutCacheKey is the Cache key + */ +class TextLayoutCacheKey { +public: + TextLayoutCacheKey() : text(NULL), start(0), count(0), contextCount(0), + dirFlags(0), textSize(0), typeface(NULL), textSkewX(0), fakeBoldText(false) { + } + + TextLayoutCacheKey(const SkPaint* paint, + const UChar* text, size_t start, size_t count, + size_t contextCount, int dirFlags) : + text(text), start(start), count(count), contextCount(contextCount), + dirFlags(dirFlags) { + textSize = paint->getTextSize(); + typeface = paint->getTypeface(); + textSkewX = paint->getTextSkewX(); + fakeBoldText = paint->isFakeBoldText(); + } + + bool operator<(const TextLayoutCacheKey& rhs) const { + LTE_INT(count) { + LTE_INT(contextCount) { + LTE_INT(start) { + LTE_FLOAT(textSize) { + LTE_INT(typeface) { + LTE_INT(textSkewX) { + LTE_INT(fakeBoldText) { + LTE_INT(dirFlags) { + return strncmp16(text, rhs.text, contextCount) < 0; + } + } + } + } + } + } + } + } + return false; + } + + // We need to copy the text when we insert the key into the cache itself. + // We don't need to copy the text when we are only comparing keys. + void internalTextCopy() { + textCopy.setTo(text, contextCount); + text = textCopy.string(); + } + + /** + * Get the size of the Cache key. + */ + size_t getSize() { + return sizeof(TextLayoutCacheKey) + sizeof(UChar) * contextCount; + } + +private: + const UChar* text; + String16 textCopy; + size_t start; + size_t count; + size_t contextCount; + int dirFlags; + float textSize; + SkTypeface* typeface; + float textSkewX; + bool fakeBoldText; +}; // TextLayoutCacheKey + +/* + * RunAdvanceDescription is the Cache entry + */ +class RunAdvanceDescription { +public: + RunAdvanceDescription() { + advances = NULL; + totalAdvance = 0; + } + + ~RunAdvanceDescription() { + delete[] advances; + } + + void setElapsedTime(uint32_t time) { + elapsedTime = time; + } + + uint32_t getElapsedTime() { + return elapsedTime; + } + + void computeAdvances(SkPaint* paint, const UChar* chars, size_t start, size_t count, + size_t contextCount, int dirFlags) { + advances = new float[count]; + this->count = count; + +#if RTL_USE_HARFBUZZ + computeAdvancesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags, + advances, &totalAdvance); +#else + computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags, + advances, &totalAdvance); +#endif +#if DEBUG_ADVANCES + LOGD("Advances - count=%d - countextCount=%d - totalAdvance=%f - " + "adv[0]=%f adv[1]=%f adv[2]=%f adv[3]=%f", count, contextCount, totalAdvance, + advances[0], advances[1], advances[2], advances[3]); +#endif + } + + void copyResult(jfloat* outAdvances, jfloat* outTotalAdvance) { + memcpy(outAdvances, advances, count * sizeof(jfloat)); + *outTotalAdvance = totalAdvance; + } + + /** + * Get the size of the Cache entry + */ + size_t getSize() { + return sizeof(RunAdvanceDescription) + sizeof(jfloat) * count; + } + + static void setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData, + SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, + int dirFlags) { + bool isRTL = dirFlags & 0x1; + + font->klass = &harfbuzzSkiaClass; + font->userData = 0; + // The values which harfbuzzSkiaClass returns are already scaled to + // pixel units, so we just set all these to one to disable further + // scaling. + font->x_ppem = 1; + font->y_ppem = 1; + font->x_scale = 1; + font->y_scale = 1; + + memset(shaperItem, 0, sizeof(*shaperItem)); + shaperItem->font = font; + shaperItem->face = HB_NewFace(shaperItem->font, harfbuzzSkiaGetTable); + + // We cannot know, ahead of time, how many glyphs a given script run + // will produce. We take a guess that script runs will not produce more + // than twice as many glyphs as there are code points plus a bit of + // padding and fallback if we find that we are wrong. + createGlyphArrays(shaperItem, (contextCount + 2) * 2); + + // Free memory for clusters if needed and recreate the clusters array + if (shaperItem->log_clusters) { + delete shaperItem->log_clusters; + } + shaperItem->log_clusters = new unsigned short[contextCount]; + + shaperItem->item.pos = start; + shaperItem->item.length = count; + shaperItem->item.bidiLevel = isRTL; + shaperItem->item.script = isRTL ? HB_Script_Arabic : HB_Script_Common; + + shaperItem->string = chars; + shaperItem->stringLength = contextCount; + + fontData->textSize = paint->getTextSize(); + fontData->fakeBold = paint->isFakeBoldText(); + fontData->fakeItalic = (paint->getTextSkewX() > 0); + fontData->typeFace = paint->getTypeface(); + + shaperItem->font->userData = fontData; + } + + static void shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData, + SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, + int dirFlags) { + // Setup Harfbuzz Shaper + setupShaperItem(shaperItem, font, fontData, paint, chars, start, count, + contextCount, dirFlags); + + // Shape + resetGlyphArrays(shaperItem); + while (!HB_ShapeItem(shaperItem)) { + // We overflowed our arrays. Resize and retry. + // HB_ShapeItem fills in shaperItem.num_glyphs with the needed size. + deleteGlyphArrays(shaperItem); + createGlyphArrays(shaperItem, shaperItem->num_glyphs << 1); + resetGlyphArrays(shaperItem); + } + } + + static void computeAdvancesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start, + size_t count, size_t contextCount, int dirFlags, + jfloat* outAdvances, jfloat* outTotalAdvance) { + + bool isRTL = dirFlags & 0x1; + + HB_ShaperItem shaperItem; + HB_FontRec font; + FontData fontData; + shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count, + contextCount, dirFlags); + +#if DEBUG_ADVANCES + LOGD("HARFBUZZ -- num_glypth=%d", shaperItem.num_glyphs); +#endif + + jfloat totalAdvance = 0; + for (size_t i = 0; i < count; i++) { + // Be careful: we need to use ceilf() for doing the same way as what Skia is doing + totalAdvance += outAdvances[i] = ceilf(HB_FIXED_TO_FLOAT(shaperItem.advances[i])); + +#if DEBUG_ADVANCES + LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i], + totalAdvance); +#endif + } + + deleteGlyphArrays(&shaperItem); + HB_FreeFace(shaperItem.face); + + *outTotalAdvance = totalAdvance; + } + + static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars, size_t start, + size_t count, size_t contextCount, int dirFlags, + jfloat* outAdvances, jfloat* outTotalAdvance) { + + SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount); + jchar* buffer = tempBuffer.get(); + + SkScalar* scalarArray = (SkScalar*)outAdvances; + + // this is where we'd call harfbuzz + // for now we just use ushape.c + size_t widths; + const jchar* text; + if (dirFlags & 0x1) { // rtl, call arabic shaping in case + UErrorCode status = U_ZERO_ERROR; + // Use fixed length since we need to keep start and count valid + u_shapeArabic(chars, contextCount, buffer, contextCount, + U_SHAPE_LENGTH_FIXED_SPACES_NEAR | + U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE | + U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); + // we shouldn't fail unless there's an out of memory condition, + // in which case we're hosed anyway + for (int i = start, e = i + count; i < e; ++i) { + if (buffer[i] == UNICODE_NOT_A_CHAR) { + buffer[i] = UNICODE_ZWSP; // zero-width-space for skia + } + } + text = buffer + start; + widths = paint->getTextWidths(text, count << 1, scalarArray); + } else { + text = chars + start; + widths = paint->getTextWidths(text, count << 1, scalarArray); + } + + jfloat totalAdvance = 0; + if (widths < count) { +#if DEBUG_ADVANCES + LOGD("ICU -- count=%d", widths); +#endif + // Skia operates on code points, not code units, so surrogate pairs return only + // one value. Expand the result so we have one value per UTF-16 code unit. + + // Note, skia's getTextWidth gets confused if it encounters a surrogate pair, + // leaving the remaining widths zero. Not nice. + for (size_t i = 0, p = 0; i < widths; ++i) { + totalAdvance += outAdvances[p++] = SkScalarToFloat(scalarArray[i]); + if (p < count && + text[p] >= UNICODE_FIRST_LOW_SURROGATE && + text[p] < UNICODE_FIRST_PRIVATE_USE && + text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE && + text[p-1] < UNICODE_FIRST_LOW_SURROGATE) { + outAdvances[p++] = 0; + } +#if DEBUG_ADVANCES + LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance); +#endif + } + } else { +#if DEBUG_ADVANCES + LOGD("ICU -- count=%d", count); +#endif + for (size_t i = 0; i < count; i++) { + totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]); +#if DEBUG_ADVANCES + LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance); +#endif + } + } + *outTotalAdvance = totalAdvance; + } + +private: + jfloat* advances; + jfloat totalAdvance; + size_t count; + + uint32_t elapsedTime; + + static void deleteGlyphArrays(HB_ShaperItem* shaperItem) { + delete[] shaperItem->glyphs; + delete[] shaperItem->attributes; + delete[] shaperItem->advances; + delete[] shaperItem->offsets; + } + + static void createGlyphArrays(HB_ShaperItem* shaperItem, int size) { + shaperItem->glyphs = new HB_Glyph[size]; + shaperItem->attributes = new HB_GlyphAttributes[size]; + shaperItem->advances = new HB_Fixed[size]; + shaperItem->offsets = new HB_FixedPoint[size]; + shaperItem->num_glyphs = size; + } + + static void resetGlyphArrays(HB_ShaperItem* shaperItem) { + int size = shaperItem->num_glyphs; + // All the types here don't have pointers. It is safe to reset to + // zero unless Harfbuzz breaks the compatibility in the future. + memset(shaperItem->glyphs, 0, size * sizeof(shaperItem->glyphs[0])); + memset(shaperItem->attributes, 0, size * sizeof(shaperItem->attributes[0])); + memset(shaperItem->advances, 0, size * sizeof(shaperItem->advances[0])); + memset(shaperItem->offsets, 0, size * sizeof(shaperItem->offsets[0])); + } + +}; // RunAdvanceDescription + + +class TextLayoutCache: public OnEntryRemoved<TextLayoutCacheKey, RunAdvanceDescription*> +{ +public: + TextLayoutCache(); + TextLayoutCache(uint32_t maxByteSize); + + virtual ~TextLayoutCache(); + + bool isInitialized() { + return mInitialized; + } + + /** + * Used as a callback when an entry is removed from the cache. + * Do not invoke directly. + */ + void operator()(TextLayoutCacheKey& text, RunAdvanceDescription*& desc); + + /** + * Get cache entries + */ + void getRunAdvances(SkPaint* paint, const jchar* text, + jint start, jint count, jint contextCount, jint dirFlags, + jfloat* outAdvances, jfloat* outTotalAdvance); + + /** + * Clear the cache + */ + void clear(); + + /** + * Sets the maximum size of the cache in bytes. + */ + void setMaxSize(uint32_t maxSize); + + /** + * Returns the maximum size of the cache in bytes. + */ + uint32_t getMaxSize(); + + /** + * Returns the current size of the cache in bytes. + */ + uint32_t getSize(); + +private: + Mutex mLock; + bool mInitialized; + + GenerationCache<TextLayoutCacheKey, RunAdvanceDescription*> mCache; + + uint32_t mSize; + uint32_t mMaxSize; + + uint32_t mCacheHitCount; + uint64_t mNanosecondsSaved; + + uint64_t mCacheStartTime; + + RtlDebugLevel mDebugLevel; + bool mDebugEnabled; + + /* + * Class initialization + */ + void init(); + + /** + * Remove oldest entries until we are having enough space + */ + void removeOldests(); + + /** + * Dump Cache statistics + */ + void dumpCacheStats(); +}; // TextLayoutCache + +} // namespace android +#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */ + diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index 56f2646..b1ea90b 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -42,8 +42,6 @@ namespace android { static struct { - jclass clazz; - jmethodID dispatchUnhandledKeyEvent; jmethodID preDispatchKeyEvent; jmethodID finish; @@ -1054,8 +1052,7 @@ static const char* const kNativeActivityPathName = "android/app/NativeActivity"; #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class %s", className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class %s", className); #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ @@ -1064,30 +1061,30 @@ static const char* const kNativeActivityPathName = "android/app/NativeActivity"; int register_android_app_NativeActivity(JNIEnv* env) { //LOGD("register_android_app_NativeActivity"); + jclass clazz; + FIND_CLASS(clazz, kNativeActivityPathName); - FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName); - GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent, - gNativeActivityClassInfo.clazz, + clazz, "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)Z"); GET_METHOD_ID(gNativeActivityClassInfo.preDispatchKeyEvent, - gNativeActivityClassInfo.clazz, + clazz, "preDispatchKeyEvent", "(Landroid/view/KeyEvent;I)V"); GET_METHOD_ID(gNativeActivityClassInfo.finish, - gNativeActivityClassInfo.clazz, + clazz, "finish", "()V"); GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags, - gNativeActivityClassInfo.clazz, + clazz, "setWindowFlags", "(II)V"); GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat, - gNativeActivityClassInfo.clazz, + clazz, "setWindowFormat", "(I)V"); GET_METHOD_ID(gNativeActivityClassInfo.showIme, - gNativeActivityClassInfo.clazz, + clazz, "showIme", "(I)V"); GET_METHOD_ID(gNativeActivityClassInfo.hideIme, - gNativeActivityClassInfo.clazz, + clazz, "hideIme", "(I)V"); return AndroidRuntime::registerNativeMethods( diff --git a/core/jni/android_content_res_Configuration.cpp b/core/jni/android_content_res_Configuration.cpp index 28a43ab..95b18ea 100644 --- a/core/jni/android_content_res_Configuration.cpp +++ b/core/jni/android_content_res_Configuration.cpp @@ -26,8 +26,6 @@ namespace android { static struct { - jclass clazz; - jfieldID mcc; jfieldID mnc; jfieldID locale; @@ -75,8 +73,7 @@ static JNINativeMethod gMethods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ @@ -84,31 +81,32 @@ static JNINativeMethod gMethods[] = { int register_android_content_res_Configuration(JNIEnv* env) { - FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration"); + jclass clazz; + FIND_CLASS(clazz, "android/content/res/Configuration"); - GET_FIELD_ID(gConfigurationClassInfo.mcc, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.mcc, clazz, "mcc", "I"); - GET_FIELD_ID(gConfigurationClassInfo.mnc, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.mnc, clazz, "mnc", "I"); - GET_FIELD_ID(gConfigurationClassInfo.locale, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.locale, clazz, "locale", "Ljava/util/Locale;"); - GET_FIELD_ID(gConfigurationClassInfo.screenLayout, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.screenLayout, clazz, "screenLayout", "I"); - GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.touchscreen, clazz, "touchscreen", "I"); - GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.keyboard, clazz, "keyboard", "I"); - GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, clazz, "keyboardHidden", "I"); - GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, clazz, "hardKeyboardHidden", "I"); - GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.navigation, clazz, "navigation", "I"); - GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, clazz, "navigationHidden", "I"); - GET_FIELD_ID(gConfigurationClassInfo.orientation, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.orientation, clazz, "orientation", "I"); - GET_FIELD_ID(gConfigurationClassInfo.uiMode, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.uiMode, clazz, "uiMode", "I"); return AndroidRuntime::registerNativeMethods(env, "android/content/res/Configuration", gMethods, diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp index 3fd7985..4759e27 100644 --- a/core/jni/android_content_res_ObbScanner.cpp +++ b/core/jni/android_content_res_ObbScanner.cpp @@ -91,8 +91,7 @@ static JNINativeMethod gMethods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ @@ -100,15 +99,16 @@ static JNINativeMethod gMethods[] = { int register_android_content_res_ObbScanner(JNIEnv* env) { - FIND_CLASS(gObbInfoClassInfo.clazz, "android/content/res/ObbInfo"); + jclass clazz; + FIND_CLASS(clazz, "android/content/res/ObbInfo"); - GET_FIELD_ID(gObbInfoClassInfo.packageName, gObbInfoClassInfo.clazz, + GET_FIELD_ID(gObbInfoClassInfo.packageName, clazz, "packageName", "Ljava/lang/String;"); - GET_FIELD_ID(gObbInfoClassInfo.version, gObbInfoClassInfo.clazz, + GET_FIELD_ID(gObbInfoClassInfo.version, clazz, "version", "I"); - GET_FIELD_ID(gObbInfoClassInfo.flags, gObbInfoClassInfo.clazz, + GET_FIELD_ID(gObbInfoClassInfo.flags, clazz, "flags", "I"); - GET_FIELD_ID(gObbInfoClassInfo.salt, gObbInfoClassInfo.clazz, + GET_FIELD_ID(gObbInfoClassInfo.salt, clazz, "salt", "[B"); return AndroidRuntime::registerNativeMethods(env, "android/content/res/ObbScanner", gMethods, @@ -116,4 +116,3 @@ int register_android_content_res_ObbScanner(JNIEnv* env) } }; // namespace android - diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp index d8a3db3..2b4a955 100644 --- a/core/jni/android_os_FileUtils.cpp +++ b/core/jni/android_os_FileUtils.cpp @@ -36,7 +36,6 @@ namespace android { -static jclass gFileStatusClass; static jfieldID gFileStatusDevFieldID; static jfieldID gFileStatusInoFieldID; static jfieldID gFileStatusModeFieldID; @@ -189,21 +188,21 @@ int register_android_os_FileUtils(JNIEnv* env) clazz = env->FindClass(kFileUtilsPathName); LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils"); - gFileStatusClass = env->FindClass("android/os/FileUtils$FileStatus"); - LOG_FATAL_IF(gFileStatusClass == NULL, "Unable to find class android.os.FileUtils$FileStatus"); - - gFileStatusDevFieldID = env->GetFieldID(gFileStatusClass, "dev", "I"); - gFileStatusInoFieldID = env->GetFieldID(gFileStatusClass, "ino", "I"); - gFileStatusModeFieldID = env->GetFieldID(gFileStatusClass, "mode", "I"); - gFileStatusNlinkFieldID = env->GetFieldID(gFileStatusClass, "nlink", "I"); - gFileStatusUidFieldID = env->GetFieldID(gFileStatusClass, "uid", "I"); - gFileStatusGidFieldID = env->GetFieldID(gFileStatusClass, "gid", "I"); - gFileStatusSizeFieldID = env->GetFieldID(gFileStatusClass, "size", "J"); - gFileStatusBlksizeFieldID = env->GetFieldID(gFileStatusClass, "blksize", "I"); - gFileStatusBlocksFieldID = env->GetFieldID(gFileStatusClass, "blocks", "J"); - gFileStatusAtimeFieldID = env->GetFieldID(gFileStatusClass, "atime", "J"); - gFileStatusMtimeFieldID = env->GetFieldID(gFileStatusClass, "mtime", "J"); - gFileStatusCtimeFieldID = env->GetFieldID(gFileStatusClass, "ctime", "J"); + jclass fileStatusClass = env->FindClass("android/os/FileUtils$FileStatus"); + LOG_FATAL_IF(fileStatusClass == NULL, "Unable to find class android.os.FileUtils$FileStatus"); + + gFileStatusDevFieldID = env->GetFieldID(fileStatusClass, "dev", "I"); + gFileStatusInoFieldID = env->GetFieldID(fileStatusClass, "ino", "I"); + gFileStatusModeFieldID = env->GetFieldID(fileStatusClass, "mode", "I"); + gFileStatusNlinkFieldID = env->GetFieldID(fileStatusClass, "nlink", "I"); + gFileStatusUidFieldID = env->GetFieldID(fileStatusClass, "uid", "I"); + gFileStatusGidFieldID = env->GetFieldID(fileStatusClass, "gid", "I"); + gFileStatusSizeFieldID = env->GetFieldID(fileStatusClass, "size", "J"); + gFileStatusBlksizeFieldID = env->GetFieldID(fileStatusClass, "blksize", "I"); + gFileStatusBlocksFieldID = env->GetFieldID(fileStatusClass, "blocks", "J"); + gFileStatusAtimeFieldID = env->GetFieldID(fileStatusClass, "atime", "J"); + gFileStatusMtimeFieldID = env->GetFieldID(fileStatusClass, "mtime", "J"); + gFileStatusCtimeFieldID = env->GetFieldID(fileStatusClass, "ctime", "J"); return AndroidRuntime::registerNativeMethods( env, kFileUtilsPathName, diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp index d2e5462..12a77d5 100644 --- a/core/jni/android_os_MessageQueue.cpp +++ b/core/jni/android_os_MessageQueue.cpp @@ -27,8 +27,6 @@ namespace android { // ---------------------------------------------------------------------------- static struct { - jclass clazz; - jfieldID mPtr; // native object attached to the DVM MessageQueue } gMessageQueueClassInfo; @@ -135,8 +133,7 @@ static JNINativeMethod gMessageQueueMethods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ @@ -147,9 +144,10 @@ int register_android_os_MessageQueue(JNIEnv* env) { gMessageQueueMethods, NELEM(gMessageQueueMethods)); LOG_FATAL_IF(res < 0, "Unable to register native methods."); - FIND_CLASS(gMessageQueueClassInfo.clazz, "android/os/MessageQueue"); + jclass clazz; + FIND_CLASS(clazz, "android/os/MessageQueue"); - GET_FIELD_ID(gMessageQueueClassInfo.mPtr, gMessageQueueClassInfo.clazz, + GET_FIELD_ID(gMessageQueueClassInfo.mPtr, clazz, "mPtr", "I"); return 0; diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp index 406884b..3c4d2bf 100644 --- a/core/jni/android_os_SystemProperties.cpp +++ b/core/jni/android_os_SystemProperties.cpp @@ -164,7 +164,7 @@ static void SystemProperties_set(JNIEnv *env, jobject clazz, if (keyJ == NULL) { jniThrowException(env, "java/lang/NullPointerException", - "key must not be null."); + "key must not be null."); return ; } key = env->GetStringUTFChars(keyJ, NULL); @@ -174,15 +174,20 @@ static void SystemProperties_set(JNIEnv *env, jobject clazz, } else { val = env->GetStringUTFChars(valJ, NULL); } - + err = property_set(key, val); - + env->ReleaseStringUTFChars(keyJ, key); - + if (valJ != NULL) { - env->ReleaseStringUTFChars(valJ, val); + env->ReleaseStringUTFChars(valJ, val); } -} + + if (err < 0) { + jniThrowException(env, "java/lang/RuntimeException", + "failed to set system property"); + } +} static JNINativeMethod method_table[] = { { "native_get", "(Ljava/lang/String;)Ljava/lang/String;", diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 1bce332..fdb7fda 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -1806,7 +1806,9 @@ int register_android_content_AssetManager(JNIEnv* env) = env->GetFieldID(assetManager, "mObject", "I"); LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject"); - g_stringClass = env->FindClass("java/lang/String"); + jclass stringClass = env->FindClass("java/lang/String"); + LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String"); + g_stringClass = (jclass)env->NewGlobalRef(stringClass); return AndroidRuntime::registerNativeMethods(env, "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods)); diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 5116f09..a4931ac 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -67,10 +67,13 @@ using namespace uirenderer; #define RENDERER_LOGD(...) #endif +#define MODIFIER_SHADOW 1 +#define MODIFIER_SHADER 2 +#define MODIFIER_COLOR_FILTER 4 + // ---------------------------------------------------------------------------- static struct { - jclass clazz; jmethodID set; } gRectClassInfo; @@ -363,6 +366,13 @@ static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject clazz, } } +static void android_view_GLES20Canvas_drawPoints(JNIEnv* env, jobject clazz, + OpenGLRenderer* renderer, jfloatArray points, jint offset, jint count, SkPaint* paint) { + jfloat* storage = env->GetFloatArrayElements(points, NULL); + renderer->drawPoints(storage + offset, count, paint); + env->ReleaseFloatArrayElements(points, storage, 0); +} + static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer, SkPath* path, SkPaint* paint) { renderer->drawPath(path, paint); @@ -371,9 +381,7 @@ static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz, static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer, jfloatArray points, jint offset, jint count, SkPaint* paint) { jfloat* storage = env->GetFloatArrayElements(points, NULL); - renderer->drawLines(storage + offset, count, paint); - env->ReleaseFloatArrayElements(points, storage, 0); } @@ -382,10 +390,10 @@ static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz, // ---------------------------------------------------------------------------- static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz, - OpenGLRenderer* renderer) { - renderer->resetShader(); - renderer->resetColorFilter(); - renderer->resetShadow(); + OpenGLRenderer* renderer, jint modifiers) { + if (modifiers & MODIFIER_SHADOW) renderer->resetShadow(); + if (modifiers & MODIFIER_SHADER) renderer->resetShader(); + if (modifiers & MODIFIER_COLOR_FILTER) renderer->resetColorFilter(); } static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz, @@ -642,11 +650,12 @@ static JNINativeMethod gMethods[] = { { "nDrawCircle", "(IFFFI)V", (void*) android_view_GLES20Canvas_drawCircle }, { "nDrawOval", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawOval }, { "nDrawArc", "(IFFFFFFZI)V", (void*) android_view_GLES20Canvas_drawArc }, + { "nDrawPoints", "(I[FIII)V", (void*) android_view_GLES20Canvas_drawPoints }, { "nDrawPath", "(III)V", (void*) android_view_GLES20Canvas_drawPath }, { "nDrawLines", "(I[FIII)V", (void*) android_view_GLES20Canvas_drawLines }, - { "nResetModifiers", "(I)V", (void*) android_view_GLES20Canvas_resetModifiers }, + { "nResetModifiers", "(II)V", (void*) android_view_GLES20Canvas_resetModifiers }, { "nSetupShader", "(II)V", (void*) android_view_GLES20Canvas_setupShader }, { "nSetupColorFilter", "(II)V", (void*) android_view_GLES20Canvas_setupColorFilter }, { "nSetupShadow", "(IFFFI)V", (void*) android_view_GLES20Canvas_setupShadow }, @@ -684,9 +693,8 @@ static JNINativeMethod gMethods[] = { #ifdef USE_OPENGL_RENDERER #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); - + LOG_FATAL_IF(! var, "Unable to find class " className); + #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ var = env->GetMethodID(clazz, methodName, methodDescriptor); \ LOG_FATAL_IF(! var, "Unable to find method " methodName); @@ -696,8 +704,9 @@ static JNINativeMethod gMethods[] = { #endif int register_android_view_GLES20Canvas(JNIEnv* env) { - FIND_CLASS(gRectClassInfo.clazz, "android/graphics/Rect"); - GET_METHOD_ID(gRectClassInfo.set, gRectClassInfo.clazz, "set", "(IIII)V"); + jclass clazz; + FIND_CLASS(clazz, "android/graphics/Rect"); + GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V"); return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp index b5a5d2e..80c4871 100644 --- a/core/jni/android_view_InputQueue.cpp +++ b/core/jni/android_view_InputQueue.cpp @@ -380,7 +380,7 @@ int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* dat #if DEBUG_DISPATCH_CYCLE LOGD("channel '%s' ~ Received motion event.", connection->getInputChannelName()); #endif - inputEventObj = android_view_MotionEvent_fromNative(env, + inputEventObj = android_view_MotionEvent_obtainAsCopy(env, static_cast<MotionEvent*>(inputEvent)); dispatchMethodId = gInputQueueClassInfo.dispatchMotionEvent; break; diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp index bfeec4f..aba3a72 100644 --- a/core/jni/android_view_KeyCharacterMap.cpp +++ b/core/jni/android_view_KeyCharacterMap.cpp @@ -30,8 +30,6 @@ static struct { } gKeyEventClassInfo; static struct { - jclass clazz; - jfieldID keyCode; jfieldID metaState; } gFallbackActionClassInfo; @@ -165,8 +163,7 @@ static JNINativeMethod g_methods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ @@ -175,13 +172,15 @@ static JNINativeMethod g_methods[] = { int register_android_text_KeyCharacterMap(JNIEnv* env) { FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); + gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz)); - FIND_CLASS(gFallbackActionClassInfo.clazz, "android/view/KeyCharacterMap$FallbackAction"); + jclass clazz; + FIND_CLASS(clazz, "android/view/KeyCharacterMap$FallbackAction"); - GET_FIELD_ID(gFallbackActionClassInfo.keyCode, gFallbackActionClassInfo.clazz, + GET_FIELD_ID(gFallbackActionClassInfo.keyCode, clazz, "keyCode", "I"); - GET_FIELD_ID(gFallbackActionClassInfo.metaState, gFallbackActionClassInfo.clazz, + GET_FIELD_ID(gFallbackActionClassInfo.metaState, clazz, "metaState", "I"); return AndroidRuntime::registerNativeMethods(env, diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 97cba23..4ce471e 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -42,8 +42,6 @@ static struct { } gMotionEventClassInfo; static struct { - jclass clazz; - jfieldID mPackedAxisBits; jfieldID mPackedAxisValues; jfieldID x; @@ -59,7 +57,10 @@ static struct { // ---------------------------------------------------------------------------- -static MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) { +MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) { + if (!eventObj) { + return NULL; + } return reinterpret_cast<MotionEvent*>( env->GetIntField(eventObj, gMotionEventClassInfo.mNativePtr)); } @@ -70,10 +71,10 @@ static void android_view_MotionEvent_setNativePtr(JNIEnv* env, jobject eventObj, reinterpret_cast<int>(event)); } -jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* event) { +jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent* event) { jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz, gMotionEventClassInfo.obtain); - if (env->ExceptionCheck()) { + if (env->ExceptionCheck() || !eventObj) { LOGE("An exception occurred while obtaining a motion event."); LOGE_EX(env); env->ExceptionClear(); @@ -90,18 +91,6 @@ jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* even return eventObj; } -status_t android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, - MotionEvent* event) { - MotionEvent* srcEvent = android_view_MotionEvent_getNativePtr(env, eventObj); - if (!srcEvent) { - LOGE("MotionEvent was finalized"); - return BAD_VALUE; - } - - event->copyFrom(srcEvent, true); - return OK; -} - status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) { env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle); if (env->ExceptionCheck()) { @@ -502,13 +491,7 @@ static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass claz static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz, jint nativePtr, jint pointerId) { MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); - size_t pointerCount = event->getPointerCount(); - for (size_t i = 0; i < pointerCount; i++) { - if (event->getPointerId(i) == pointerId) { - return i; - } - } - return -1; + return jint(event->findPointerIndex(pointerId)); } static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz, @@ -734,8 +717,7 @@ static JNINativeMethod gMotionEventMethods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \ @@ -755,6 +737,7 @@ int register_android_view_MotionEvent(JNIEnv* env) { LOG_FATAL_IF(res < 0, "Unable to register native methods."); FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent"); + gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz)); GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz, "obtain", "()Landroid/view/MotionEvent;"); @@ -763,29 +746,30 @@ int register_android_view_MotionEvent(JNIEnv* env) { GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz, "mNativePtr", "I"); - FIND_CLASS(gPointerCoordsClassInfo.clazz, "android/view/MotionEvent$PointerCoords"); + jclass clazz; + FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords"); - GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz, "mPackedAxisBits", "J"); - GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz, "mPackedAxisValues", "[F"); - GET_FIELD_ID(gPointerCoordsClassInfo.x, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz, "x", "F"); - GET_FIELD_ID(gPointerCoordsClassInfo.y, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz, "y", "F"); - GET_FIELD_ID(gPointerCoordsClassInfo.pressure, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz, "pressure", "F"); - GET_FIELD_ID(gPointerCoordsClassInfo.size, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz, "size", "F"); - GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz, "touchMajor", "F"); - GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz, "touchMinor", "F"); - GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz, "toolMajor", "F"); - GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz, "toolMinor", "F"); - GET_FIELD_ID(gPointerCoordsClassInfo.orientation, gPointerCoordsClassInfo.clazz, + GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz, "orientation", "F"); return 0; diff --git a/core/jni/android_view_MotionEvent.h b/core/jni/android_view_MotionEvent.h index 80dc861..0cf1fb2 100644 --- a/core/jni/android_view_MotionEvent.h +++ b/core/jni/android_view_MotionEvent.h @@ -26,12 +26,11 @@ class MotionEvent; /* Obtains an instance of a DVM MotionEvent object as a copy of a native MotionEvent instance. * Returns NULL on error. */ -extern jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* event); +extern jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent* event); -/* Copies the contents of a DVM MotionEvent object to a native MotionEvent instance. - * Returns non-zero on error. */ -extern status_t android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, - MotionEvent* event); +/* Gets the underlying native MotionEvent instance within a DVM MotionEvent object. + * Returns NULL if the event is NULL or if it is uninitialized. */ +extern MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj); /* Recycles a DVM MotionEvent object. * Returns non-zero on error. */ diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index bd2e669..9f1b1fd 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -378,7 +378,7 @@ static void Surface_unlockCanvasAndPost( JNIEnv* env, jobject clazz, jobject argCanvas) { jobject canvas = env->GetObjectField(clazz, so.canvas); - if (canvas != argCanvas) { + if (env->IsSameObject(canvas, argCanvas) == JNI_FALSE) { doThrow(env, "java/lang/IllegalArgumentException", NULL); return; } diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp new file mode 100644 index 0000000..daa0adc --- /dev/null +++ b/core/jni/android_view_VelocityTracker.cpp @@ -0,0 +1,208 @@ +/* + * 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 "VelocityTracker-JNI" + +#include "JNIHelp.h" + +#include <android_runtime/AndroidRuntime.h> +#include <utils/Log.h> +#include <ui/Input.h> +#include "android_view_MotionEvent.h" + + +namespace android { + +// Special constant to request the velocity of the active pointer. +static const int ACTIVE_POINTER_ID = -1; + +// --- VelocityTrackerState --- + +class VelocityTrackerState { +public: + VelocityTrackerState(); + + void clear(); + void addMovement(const MotionEvent* event); + void computeCurrentVelocity(int32_t units, float maxVelocity); + void getVelocity(int32_t id, float* outVx, float* outVy); + +private: + struct Velocity { + float vx, vy; + }; + + VelocityTracker mVelocityTracker; + int32_t mActivePointerId; + BitSet32 mCalculatedIdBits; + Velocity mCalculatedVelocity[MAX_POINTERS]; +}; + +VelocityTrackerState::VelocityTrackerState() : mActivePointerId(-1) { +} + +void VelocityTrackerState::clear() { + mVelocityTracker.clear(); + mActivePointerId = -1; + mCalculatedIdBits.clear(); +} + +void VelocityTrackerState::addMovement(const MotionEvent* event) { + mVelocityTracker.addMovement(event); +} + +void VelocityTrackerState::computeCurrentVelocity(int32_t units, float maxVelocity) { + BitSet32 idBits(mVelocityTracker.getCurrentPointerIdBits()); + mCalculatedIdBits = idBits; + + for (uint32_t index = 0; !idBits.isEmpty(); index++) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + + float vx, vy; + mVelocityTracker.getVelocity(id, &vx, &vy); + + vx = vx * units / 1000; + vy = vy * units / 1000; + + if (vx > maxVelocity) { + vx = maxVelocity; + } else if (vx < -maxVelocity) { + vx = -maxVelocity; + } + if (vy > maxVelocity) { + vy = maxVelocity; + } else if (vy < -maxVelocity) { + vy = -maxVelocity; + } + + Velocity& velocity = mCalculatedVelocity[index]; + velocity.vx = vx; + velocity.vy = vy; + } +} + +void VelocityTrackerState::getVelocity(int32_t id, float* outVx, float* outVy) { + if (id == ACTIVE_POINTER_ID) { + id = mVelocityTracker.getActivePointerId(); + } + + float vx, vy; + if (id >= 0 && id <= MAX_POINTER_ID && mCalculatedIdBits.hasBit(id)) { + uint32_t index = mCalculatedIdBits.getIndexOfBit(id); + const Velocity& velocity = mCalculatedVelocity[index]; + vx = velocity.vx; + vy = velocity.vy; + } else { + vx = 0; + vy = 0; + } + + if (outVx) { + *outVx = vx; + } + if (outVy) { + *outVy = vy; + } +} + + +// --- JNI Methods --- + +static jint android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz) { + return reinterpret_cast<jint>(new VelocityTrackerState()); +} + +static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jint ptr) { + VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); + delete state; +} + +static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jint ptr) { + VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); + state->clear(); +} + +static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jint ptr, + jobject eventObj) { + const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj); + if (!event) { + LOGW("nativeAddMovement failed because MotionEvent was finalized."); + return; + } + + VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); + state->addMovement(event); +} + +static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz, + jint ptr, jint units, jfloat maxVelocity) { + VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); + state->computeCurrentVelocity(units, maxVelocity); +} + +static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz, + jint ptr, jint id) { + VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); + float vx; + state->getVelocity(id, &vx, NULL); + return vx; +} + +static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz, + jint ptr, jint id) { + VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); + float vy; + state->getVelocity(id, NULL, &vy); + return vy; +} + + +// --- JNI Registration --- + +static JNINativeMethod gVelocityTrackerMethods[] = { + /* name, signature, funcPtr */ + { "nativeInitialize", + "()I", + (void*)android_view_VelocityTracker_nativeInitialize }, + { "nativeDispose", + "(I)V", + (void*)android_view_VelocityTracker_nativeDispose }, + { "nativeClear", + "(I)V", + (void*)android_view_VelocityTracker_nativeClear }, + { "nativeAddMovement", + "(ILandroid/view/MotionEvent;)V", + (void*)android_view_VelocityTracker_nativeAddMovement }, + { "nativeComputeCurrentVelocity", + "(IIF)V", + (void*)android_view_VelocityTracker_nativeComputeCurrentVelocity }, + { "nativeGetXVelocity", + "(II)F", + (void*)android_view_VelocityTracker_nativeGetXVelocity }, + { "nativeGetYVelocity", + "(II)F", + (void*)android_view_VelocityTracker_nativeGetYVelocity }, +}; + +int register_android_view_VelocityTracker(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "android/view/VelocityTracker", + gVelocityTrackerMethods, NELEM(gVelocityTrackerMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + return 0; +} + +} // namespace android diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml index 15dfea3..4a73368 100644 --- a/core/res/res/layout/action_menu_item_layout.xml +++ b/core/res/res/layout/action_menu_item_layout.xml @@ -24,7 +24,8 @@ android:paddingLeft="12dip" android:paddingRight="12dip" android:minWidth="64dip" - android:minHeight="?attr/actionBarSize"> + android:minHeight="?attr/actionBarSize" + android:focusable="true"> <ImageButton android:id="@+id/imageButton" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -34,7 +35,8 @@ android:paddingRight="4dip" android:minHeight="56dip" android:scaleType="center" - android:background="@null" /> + android:background="@null" + android:focusable="false" /> <Button android:id="@+id/textButton" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -45,5 +47,6 @@ android:textColor="?attr/actionMenuTextColor" android:background="@null" android:paddingLeft="4dip" - android:paddingRight="4dip" /> + android:paddingRight="4dip" + android:focusable="false" /> </com.android.internal.view.menu.ActionMenuItemView> diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml index 5d034a5..925b715 100644 --- a/core/res/res/layout/preference_list_content.xml +++ b/core/res/res/layout/preference_list_content.xml @@ -36,8 +36,6 @@ android:layout_height="match_parent" android:layout_marginRight="@dimen/preference_screen_side_margin_negative" android:layout_marginLeft="@dimen/preference_screen_side_margin" - android:layout_marginTop="32dp" - android:layout_marginBottom="32dp" android:layout_weight="10"> <ListView android:id="@android:id/list" @@ -61,33 +59,9 @@ android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="20" - android:layout_marginLeft="@dimen/preference_screen_side_margin" - android:layout_marginRight="@dimen/preference_screen_side_margin" - android:layout_marginTop="16dp" - android:layout_marginBottom="16dp" - android:background="?attr/detailsElementBackground" android:orientation="vertical" android:visibility="gone" > - <!-- Breadcrumb inserted here --> - <android.app.FragmentBreadCrumbs - android:id="@android:id/title" - android:layout_height="72dip" - android:layout_width="match_parent" - android:paddingTop="16dip" - android:paddingBottom="8dip" - android:gravity="center_vertical|left" - android:layout_marginLeft="48dip" - android:layout_marginRight="48dip" - /> - - <ImageView - android:layout_width="match_parent" - android:layout_height="1dip" - android:paddingLeft="32dip" - android:paddingRight="32dip" - android:src="#404040" - /> <android.preference.PreferenceFrameLayout android:id="@+id/prefs" android:layout_width="match_parent" android:layout_height="0dip" diff --git a/core/res/res/layout/preference_list_content_large.xml b/core/res/res/layout/preference_list_content_large.xml new file mode 100644 index 0000000..14d188e --- /dev/null +++ b/core/res/res/layout/preference_list_content_large.xml @@ -0,0 +1,140 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/layout/list_content.xml +** +** 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. +*/ +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1"> + + <LinearLayout + android:id="@+id/headers" + android:orientation="vertical" + android:layout_width="0px" + android:layout_height="match_parent" + android:layout_marginRight="@dimen/preference_screen_side_margin_negative" + android:layout_marginLeft="@dimen/preference_screen_side_margin" + android:layout_marginTop="32dp" + android:layout_marginBottom="32dp" + android:layout_weight="10"> + + <ListView android:id="@android:id/list" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1" + android:drawSelectorOnTop="false" + android:cacheColorHint="@android:color/transparent" + android:listPreferredItemHeight="48dp" + android:scrollbarAlwaysDrawVerticalTrack="true" /> + + <FrameLayout android:id="@+id/list_footer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="0" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/prefs_frame" + android:layout_width="0px" + android:layout_height="match_parent" + android:layout_weight="20" + android:layout_marginLeft="@dimen/preference_screen_side_margin" + android:layout_marginRight="@dimen/preference_screen_side_margin" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp" + android:background="?attr/detailsElementBackground" + android:orientation="vertical" + android:visibility="gone" > + + <!-- Breadcrumb inserted here --> + <android.app.FragmentBreadCrumbs + android:id="@android:id/title" + android:layout_height="72dip" + android:layout_width="match_parent" + android:paddingTop="16dip" + android:paddingBottom="8dip" + android:gravity="center_vertical|left" + android:layout_marginLeft="48dip" + android:layout_marginRight="48dip" + /> + + <ImageView + android:layout_width="match_parent" + android:layout_height="1dip" + android:paddingLeft="32dip" + android:paddingRight="32dip" + android:src="#404040" + /> + <android.preference.PreferenceFrameLayout android:id="@+id/prefs" + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_weight="1" + android:layout_marginTop="-1dip" + /> + </LinearLayout> + </LinearLayout> + + <RelativeLayout android:id="@+id/button_bar" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_weight="0" + android:background="@android:drawable/bottom_bar" + android:visibility="gone"> + + <Button android:id="@+id/back_button" + android:layout_width="150dip" + android:layout_height="wrap_content" + android:layout_margin="5dip" + android:layout_alignParentLeft="true" + android:drawableLeft="@drawable/ic_btn_back" + android:drawablePadding="3dip" + android:text="@string/back_button_label" + /> + <LinearLayout + android:orientation="horizontal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true"> + + <Button android:id="@+id/skip_button" + android:layout_width="150dip" + android:layout_height="wrap_content" + android:layout_margin="5dip" + android:text="@string/skip_button_label" + android:visibility="gone" + /> + + <Button android:id="@+id/next_button" + android:layout_width="150dip" + android:layout_height="wrap_content" + android:layout_margin="5dip" + android:drawableRight="@drawable/ic_btn_next" + android:drawablePadding="3dip" + android:text="@string/next_button_label" + /> + </LinearLayout> + </RelativeLayout> +</LinearLayout> diff --git a/core/res/res/layout-xlarge/preference_list_content_single.xml b/core/res/res/layout/preference_list_content_single_large.xml index 6725996..6725996 100644 --- a/core/res/res/layout-xlarge/preference_list_content_single.xml +++ b/core/res/res/layout/preference_list_content_single_large.xml diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml index 393cecf..4044371 100644 --- a/core/res/res/layout/preference_list_fragment.xml +++ b/core/res/res/layout/preference_list_fragment.xml @@ -28,10 +28,6 @@ android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="1" - android:paddingTop="0dip" - android:paddingBottom="48dip" - android:paddingLeft="32dip" - android:paddingRight="32dip" android:clipToPadding="false" android:drawSelectorOnTop="false" android:cacheColorHint="@android:color/transparent" diff --git a/core/res/res/layout/preference_list_fragment_large.xml b/core/res/res/layout/preference_list_fragment_large.xml new file mode 100644 index 0000000..cde84ff --- /dev/null +++ b/core/res/res/layout/preference_list_fragment_large.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** 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. +*/ +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:background="@android:color/transparent" + android:layout_removeBorders="true"> + + <ListView android:id="@android:id/list" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1" + android:paddingTop="0dip" + android:paddingBottom="48dip" + android:paddingLeft="32dip" + android:paddingRight="32dip" + android:clipToPadding="false" + android:drawSelectorOnTop="false" + android:cacheColorHint="@android:color/transparent" + android:scrollbarAlwaysDrawVerticalTrack="true" /> + + <RelativeLayout android:id="@+id/button_bar" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_weight="0" + android:background="@android:drawable/bottom_bar" + android:visibility="gone"> + + <Button android:id="@+id/back_button" + android:layout_width="150dip" + android:layout_height="wrap_content" + android:layout_margin="5dip" + android:layout_alignParentLeft="true" + android:drawableLeft="@drawable/ic_btn_back" + android:drawablePadding="3dip" + android:text="@string/back_button_label" + /> + <LinearLayout + android:orientation="horizontal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true"> + + <Button android:id="@+id/skip_button" + android:layout_width="150dip" + android:layout_height="wrap_content" + android:layout_margin="5dip" + android:text="@string/skip_button_label" + android:visibility="gone" + /> + + <Button android:id="@+id/next_button" + android:layout_width="150dip" + android:layout_height="wrap_content" + android:layout_margin="5dip" + android:drawableRight="@drawable/ic_btn_next" + android:drawablePadding="3dip" + android:text="@string/next_button_label" + /> + </LinearLayout> + </RelativeLayout> +</LinearLayout> diff --git a/core/res/res/layout/tab_indicator_holo.xml b/core/res/res/layout/tab_indicator_holo.xml index d37476b..60c80e9 100644 --- a/core/res/res/layout/tab_indicator_holo.xml +++ b/core/res/res/layout/tab_indicator_holo.xml @@ -15,32 +15,24 @@ --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="56dip" - android:layout_weight="0" - android:layout_marginLeft="0dip" - android:layout_marginRight="0dip" + android:layout_width="0dp" + android:layout_height="58dp" + android:layout_weight="1" + android:layout_marginLeft="-3dip" + android:layout_marginRight="-3dip" + android:paddingBottom="8dp" android:background="@android:drawable/tab_indicator_holo"> - <View android:id="@+id/tab_indicator_left_spacer" - android:layout_width="16dip" - android:layout_height="0dip" /> - <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:visibility="gone" - android:layout_toRightOf="@id/tab_indicator_left_spacer" - android:paddingRight="8dip" /> + android:layout_centerHorizontal="true" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:layout_toRightOf="@id/icon" - android:paddingLeft="0dip" - android:paddingRight="16dip" + android:layout_alignParentBottom="true" + android:layout_centerHorizontal="true" style="?android:attr/tabWidgetStyle" /> - + </RelativeLayout> diff --git a/core/res/res/layout/tab_indicator_holo_large.xml b/core/res/res/layout/tab_indicator_holo_large.xml new file mode 100644 index 0000000..bdd8d11 --- /dev/null +++ b/core/res/res/layout/tab_indicator_holo_large.xml @@ -0,0 +1,46 @@ +<?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. +--> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="56dip" + android:layout_weight="0" + android:layout_marginLeft="0dip" + android:layout_marginRight="0dip" + android:background="@android:drawable/tab_indicator_holo"> + + <View android:id="@+id/tab_indicator_left_spacer" + android:layout_width="16dip" + android:layout_height="0dip" /> + + <ImageView android:id="@+id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:visibility="gone" + android:layout_toRightOf="@id/tab_indicator_left_spacer" + android:paddingRight="8dip" /> + + <TextView android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_toRightOf="@id/icon" + android:paddingLeft="0dip" + android:paddingRight="16dip" + style="?android:attr/tabWidgetStyle" /> + +</RelativeLayout> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index d8c64f0..25e66b4 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -987,7 +987,7 @@ <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g>"</item> </plurals> <string name="action_mode_done" msgid="7217581640461922289">"Gotovo"</string> - <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"Isključivanje USB memorije..."</string> + <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"Isključivanje memorije USB..."</string> <string name="progress_unmounting" product="default" msgid="5556813978958789471">"Isključivanje SD kartice..."</string> <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Brisanje memorije USB..."</string> <string name="progress_erasing" product="default" msgid="2115214724367534095">"Brisanje SD kartice..."</string> diff --git a/core/res/res/values-large/dimens.xml b/core/res/res/values-large/dimens.xml index 5691548..cd1847f 100644 --- a/core/res/res/values-large/dimens.xml +++ b/core/res/res/values-large/dimens.xml @@ -19,4 +19,7 @@ <resources> <item type="dimen" name="dialog_min_width_major">55%</item> <item type="dimen" name="dialog_min_width_minor">80%</item> + + <!-- Preference UI dimensions for larger screens. --> + <dimen name="preference_widget_width">56dp</dimen> </resources> diff --git a/core/res/res/values-large/styles.xml b/core/res/res/values-large/styles.xml new file mode 100644 index 0000000..96a8c84 --- /dev/null +++ b/core/res/res/values-large/styles.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> + <style name="Widget.Holo.PreferenceFrameLayout"> + <item name="android:borderTop">0dip</item> + <item name="android:borderBottom">48dip</item> + <item name="android:borderLeft">32dip</item> + <item name="android:borderRight">32dip</item> + </style> +</resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 1c4ff09..10a2898 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -825,7 +825,7 @@ <string name="anr_application_process" msgid="4185842666452210193">"Приложение <xliff:g id="APPLICATION">%1$s</xliff:g> (в процессе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string> <string name="anr_process" msgid="1246866008169975783">"Процесс <xliff:g id="PROCESS">%1$s</xliff:g> не отвечает."</string> <string name="force_close" msgid="3653416315450806396">"Закрыть"</string> - <string name="report" msgid="4060218260984795706">"Отзыв"</string> + <string name="report" msgid="4060218260984795706">"Отчет"</string> <string name="wait" msgid="7147118217226317732">"Подождать"</string> <string name="launch_warning_title" msgid="8323761616052121936">"Приложение перенаправлено"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> выполняется."</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index ad4eee7..58b681e 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -896,7 +896,7 @@ <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"USB depolama birimini açarsanız, kullanmakta olduğunuz bazı uygulamalar durur ve USB depolama birimi kapatılıncaya kadar kullanılamayabilir."</string> <string name="dlg_error_title" msgid="8048999973837339174">"USB işlemi başarısız oldu"</string> <string name="dlg_ok" msgid="7376953167039865701">"Tamam"</string> - <string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB\'yi biçimlendir"</string> + <string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB dep br biçimlndr"</string> <string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SD kartı biçimlendir"</string> <string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"USB depolama birimi biçimlendirilsin mi? Depolama biriminde saklanan tüm dosyalar silinir. İşlem geri alınamaz!"</string> <string name="extmedia_format_message" product="default" msgid="3621369962433523619">"SD kartı biçimlendirmek istediğinizden emin misiniz? Kartınızdaki tüm veriler yok olacak."</string> diff --git a/core/res/res/values-xlarge/styles.xml b/core/res/res/values-xlarge/styles.xml index dd78920..a39d9d6 100644 --- a/core/res/res/values-xlarge/styles.xml +++ b/core/res/res/values-xlarge/styles.xml @@ -36,6 +36,22 @@ <item name="android:textColor">?android:attr/textColorPrimary</item> </style> + <style name="TextAppearance.Holo.Widget.TabWidget"> + <item name="android:textSize">18sp</item> + <item name="android:textStyle">normal</item> + <item name="android:textColor">@android:color/tab_indicator_text</item> + </style> + + <style name="Widget.Holo.TabWidget" parent="Widget.TabWidget"> + <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item> + <item name="android:tabStripLeft">@null</item> + <item name="android:tabStripRight">@null</item> + <item name="android:tabStripEnabled">false</item> + <item name="android:divider">@null</item> + <item name="android:gravity">left|center_vertical</item> + <item name="android:tabLayout">@android:layout/tab_indicator_holo_large</item> + </style> + <style name="PreferencePanel"> <item name="android:layout_marginLeft">@dimen/preference_screen_side_margin</item> <item name="android:layout_marginRight">@dimen/preference_screen_side_margin</item> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 71a8b2a..e2c440a 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1374,6 +1374,9 @@ <enum name="KEYCODE_BUTTON_14" value="201" /> <enum name="KEYCODE_BUTTON_15" value="202" /> <enum name="KEYCODE_BUTTON_16" value="203" /> + <enum name="KEYCODE_LANGUAGE_SWITCH" value="204" /> + <enum name="KEYCODE_MANNER_MODE" value="205" /> + <enum name="KEYCODE_3D_MODE" value="206" /> </attr> <!-- ***************************************************************** --> @@ -3814,6 +3817,7 @@ <li>"state_rect" <li>"state_grow" <li>"state_move" + <li>"state_hovered" </ul> --> <declare-styleable name="DrawableStates"> <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}, @@ -3863,6 +3867,9 @@ ignored even if it specifies a solid color, since that optimization is not needed. --> <attr name="state_accelerated" format="boolean" /> + <!-- State value for {@link android.graphics.drawable.StateListDrawable StateListDrawable}, + set when a pointer is hovering over the view. --> + <attr name="state_hovered" format="boolean" /> </declare-styleable> <declare-styleable name="ViewDrawableStates"> <attr name="state_pressed" /> @@ -3872,6 +3879,7 @@ <attr name="state_enabled" /> <attr name="state_activated" /> <attr name="state_accelerated" /> + <attr name="state_hovered" /> </declare-styleable> <!-- State array representing a menu item that is currently checked. --> <declare-styleable name="MenuItemCheckedState"> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 2037191..56bc1d3 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -544,6 +544,9 @@ which typically is /data/data/com.android.providers.downloads/files --> <integer name="config_downloadDataDirSize">100</integer> + <!-- Max number of downloads allowed to proceed concurrently --> + <integer name="config_MaxConcurrentDownloadsAllowed">5</integer> + <!-- When the free space available in DownloadManager's data dir falls below the percentage value specified by this param, DownloadManager starts removing files to try to make percentage of available diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 8a590cd..cca7d8b 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -52,12 +52,13 @@ <dimen name="password_keyboard_key_height_numeric">56dip</dimen> <!-- Default correction for the space key in the password keyboard --> <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen> + <!-- Preference activity side margins --> <dimen name="preference_screen_side_margin">0dp</dimen> <!-- Preference activity side margins negative--> <dimen name="preference_screen_side_margin_negative">0dp</dimen> <!-- Preference widget area width (to the left of the text) --> - <dimen name="preference_widget_width">56dp</dimen> + <dimen name="preference_widget_width">8dp</dimen> <!-- The platform's desired minimum size for a dialog's width when it is along the major axis (that is the screen is landscape). This may diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index f1ec398..5432212 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1648,4 +1648,11 @@ <eat-comment /> <public type="attr" name="textCursorDrawable" id="0x01010362" /> <public type="attr" name="resizeMode" /> + +<!-- =============================================================== + Resources added in version 13 of the platform (Ice Cream Sandwich) + =============================================================== --> + <eat-comment /> + <public type="attr" name="state_hovered" /> + </resources> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 11c3916..f7d3c3f 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1214,8 +1214,10 @@ <item name="android:textColor">?textColorPrimary</item> </style> + <!-- This style is for smaller screens; values-xlarge defines a version + for larger screens. --> <style name="TextAppearance.Holo.Widget.TabWidget"> - <item name="android:textSize">18sp</item> + <item name="android:textSize">14sp</item> <item name="android:textStyle">normal</item> <item name="android:textColor">@android:color/tab_indicator_text</item> </style> @@ -1664,6 +1666,9 @@ <item name="android:button">@android:drawable/btn_star_holo_dark</item> </style> + <!-- The holo style for smaller screens actually uses the non-holo layout, + which is more compact. values-xlarge defines an alternative version + for the real holo look on a large screen. --> <style name="Widget.Holo.TabWidget" parent="Widget.TabWidget"> <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item> <item name="android:tabStripLeft">@null</item> @@ -2179,8 +2184,8 @@ <style name="Widget.Holo.PreferenceFrameLayout"> <item name="android:borderTop">0dip</item> - <item name="android:borderBottom">48dip</item> - <item name="android:borderLeft">32dip</item> - <item name="android:borderRight">32dip</item> + <item name="android:borderBottom">0dip</item> + <item name="android:borderLeft">0dip</item> + <item name="android:borderRight">0dip</item> </style> </resources> diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java index 39258ae..5ef8d11 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java @@ -31,9 +31,11 @@ import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.Suppress; import android.util.Log; +import android.util.Pair; import java.io.File; import java.util.ArrayList; +import java.util.List; public class SQLiteDatabaseTest extends AndroidTestCase { private static final String TAG = "DatabaseGeneralTest"; @@ -892,6 +894,49 @@ public class SQLiteDatabaseTest extends AndroidTestCase { c.close(); } + @SmallTest + public void testAttachDb() { + String newDb = "/sdcard/mydata.db"; + File f = new File(newDb); + if (f.exists()) { + f.delete(); + } + assertFalse(f.exists()); + SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(newDb, null); + db.execSQL("create table test1 (i int);"); + db.execSQL("insert into test1 values(1);"); + db.execSQL("insert into test1 values(11);"); + Cursor c = null; + try { + c = db.rawQuery("select * from test1", null); + int count = c.getCount(); + Log.i(TAG, "count: " + count); + assertEquals(2, count); + } finally { + c.close(); + db.close(); + c = null; + } + + mDatabase.execSQL("attach database ? as newDb" , new String[]{newDb}); + Cursor c1 = null; + try { + c1 = mDatabase.rawQuery("select * from newDb.test1", null); + assertEquals(2, c1.getCount()); + } catch (Exception e) { + fail("unexpected exception: " + e.getMessage()); + } finally { + if (c1 != null) { + c1.close(); + } + } + List<Pair<String, String>> dbs = mDatabase.getAttachedDbs(); + for (Pair<String, String> p: dbs) { + Log.i(TAG, "attached dbs: " + p.first + " : " + p.second); + } + assertEquals(2, dbs.size()); + } + /** * http://b/issue?id=2943028 * SQLiteOpenHelper maintains a Singleton even if it is in bad state. diff --git a/core/tests/coretests/src/android/os/MemoryFileTest.java b/core/tests/coretests/src/android/os/MemoryFileTest.java index e627bb4..82af662 100644 --- a/core/tests/coretests/src/android/os/MemoryFileTest.java +++ b/core/tests/coretests/src/android/os/MemoryFileTest.java @@ -20,13 +20,11 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class MemoryFileTest extends AndroidTestCase { @@ -101,6 +99,25 @@ public class MemoryFileTest extends AndroidTestCase { file.close(); } + // http://code.google.com/p/android/issues/detail?id=11415 + public void testOutputStreamAdvances() throws IOException { + MemoryFile file = new MemoryFile("MemoryFileTest", 10); + + OutputStream os = file.getOutputStream(); + os.write(new byte[] { 1, 2, 3, 4, 5 }); + os.write(new byte[] { -1, -1, 6, 7, 8, -1 }, 2, 3); + os.write(9); + try { + os.write(new byte[] { -1, -1 }); + fail(); + } catch (IndexOutOfBoundsException expected) { + } + + byte[] copy = new byte[file.length()]; + file.readBytes(copy, 0, 0, file.length()); + assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]", Arrays.toString(copy)); + } + // Tests for the IndexOutOfBoundsException cases in read(). private void readIndexOutOfBoundsException(int offset, int count, String msg) diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java index e111662..e8e56de 100644 --- a/core/tests/coretests/src/android/text/TextUtilsTest.java +++ b/core/tests/coretests/src/android/text/TextUtilsTest.java @@ -16,28 +16,20 @@ package android.text; -import android.graphics.Paint; +import com.google.android.collect.Lists; + +import android.test.MoreAsserts; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.SpannedString; -import android.text.TextPaint; -import android.text.TextUtils; import android.text.style.StyleSpan; import android.text.util.Rfc822Token; import android.text.util.Rfc822Tokenizer; -import android.test.MoreAsserts; -import com.google.android.collect.Lists; -import com.google.android.collect.Maps; +import java.util.ArrayList; +import java.util.List; import junit.framework.TestCase; -import java.util.List; -import java.util.Map; - /** * TextUtilsTest tests {@link TextUtils}. */ @@ -354,6 +346,7 @@ public class TextUtilsTest extends TestCase { return mString.charAt(off); } + @Override public String toString() { return mString.toString(); } @@ -362,4 +355,104 @@ public class TextUtilsTest extends TestCase { return new Wrapper(mString.subSequence(start, end)); } } + + @LargeTest + public void testRemoveEmptySpans() { + MockSpanned spanned = new MockSpanned(); + + spanned.test(); + spanned.addSpan().test(); + spanned.addSpan().test(); + spanned.addSpan().test(); + spanned.addEmptySpan().test(); + spanned.addSpan().test(); + spanned.addEmptySpan().test(); + spanned.addEmptySpan().test(); + spanned.addSpan().test(); + + spanned.clear(); + spanned.addEmptySpan().test(); + spanned.addEmptySpan().test(); + spanned.addEmptySpan().test(); + spanned.addSpan().test(); + spanned.addEmptySpan().test(); + spanned.addSpan().test(); + + spanned.clear(); + spanned.addSpan().test(); + spanned.addEmptySpan().test(); + spanned.addSpan().test(); + spanned.addEmptySpan().test(); + spanned.addSpan().test(); + spanned.addSpan().test(); + } + + protected static class MockSpanned implements Spanned { + + private List<Object> allSpans = new ArrayList<Object>(); + private List<Object> nonEmptySpans = new ArrayList<Object>(); + + public void clear() { + allSpans.clear(); + nonEmptySpans.clear(); + } + + public MockSpanned addSpan() { + Object o = new Object(); + allSpans.add(o); + nonEmptySpans.add(o); + return this; + } + + public MockSpanned addEmptySpan() { + Object o = new Object(); + allSpans.add(o); + return this; + } + + public void test() { + Object[] nonEmpty = TextUtils.removeEmptySpans(allSpans.toArray(), this, Object.class); + assertEquals("Mismatched array size", nonEmptySpans.size(), nonEmpty.length); + for (int i=0; i<nonEmpty.length; i++) { + assertEquals("Span differ", nonEmptySpans.get(i), nonEmpty[i]); + } + } + + public char charAt(int arg0) { + return 0; + } + + public int length() { + return 0; + } + + public CharSequence subSequence(int arg0, int arg1) { + return null; + } + + @Override + public <T> T[] getSpans(int start, int end, Class<T> type) { + return null; + } + + @Override + public int getSpanStart(Object tag) { + return 0; + } + + @Override + public int getSpanEnd(Object tag) { + return nonEmptySpans.contains(tag) ? 1 : 0; + } + + @Override + public int getSpanFlags(Object tag) { + return 0; + } + + @Override + public int nextSpanTransition(int start, int limit, Class type) { + return 0; + } + } } diff --git a/core/tests/systemproperties/AndroidManifest.xml b/core/tests/systemproperties/AndroidManifest.xml index ad0abf4..1608788 100644 --- a/core/tests/systemproperties/AndroidManifest.xml +++ b/core/tests/systemproperties/AndroidManifest.xml @@ -24,7 +24,7 @@ </application> <instrumentation android:name="android.test.InstrumentationTestRunner" - android:targetPackage="com.android.frameworks.coretests" - android:label="Frameworks Core Tests" /> + android:targetPackage="com.android.frameworks.coretests.systemproperties" + android:label="Frameworks SystemProperties Core Tests" /> </manifest> diff --git a/core/tests/systemproperties/run_core_systemproperties_test.sh b/core/tests/systemproperties/run_core_systemproperties_test.sh index 48880f3..d39adbb 100755 --- a/core/tests/systemproperties/run_core_systemproperties_test.sh +++ b/core/tests/systemproperties/run_core_systemproperties_test.sh @@ -16,6 +16,9 @@ fi if [[ $rebuild == true ]]; then make -j4 FrameworksCoreSystemPropertiesTests TESTAPP=${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreSystemPropertiesTests.apk + COMMAND="adb install -r $TESTAPP" + echo $COMMAND + $COMMAND fi adb shell am instrument -w -e class android.os.SystemPropertiesTest com.android.frameworks.coretests.systemproperties/android.test.InstrumentationTestRunner diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp index 8d115a8..27a5a2d 100644 --- a/drm/common/DrmInfoEvent.cpp +++ b/drm/common/DrmInfoEvent.cpp @@ -19,7 +19,7 @@ using namespace android; -DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8& message) +DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message) : mUniqueId(uniqueId), mInfoType(infoType), mMessage(message) { @@ -34,7 +34,7 @@ int DrmInfoEvent::getType() const { return mInfoType; } -const String8& DrmInfoEvent::getMessage() const { +const String8 DrmInfoEvent::getMessage() const { return mMessage; } diff --git a/drm/common/DrmSupportInfo.cpp b/drm/common/DrmSupportInfo.cpp index c0bff0e..3dee435 100644 --- a/drm/common/DrmSupportInfo.cpp +++ b/drm/common/DrmSupportInfo.cpp @@ -15,6 +15,7 @@ */ #include <drm/DrmSupportInfo.h> +#include <strings.h> using namespace android; @@ -152,4 +153,3 @@ String8& DrmSupportInfo::MimeTypeIterator::next() { mIndex++; return value; } - diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp index 346934b..c37b4f8 100644 --- a/drm/common/IDrmManagerService.cpp +++ b/drm/common/IDrmManagerService.cpp @@ -650,11 +650,6 @@ status_t BpDrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* d remote()->transact(CLOSE_DECRYPT_SESSION, data, &reply); - if (NULL != decryptHandle->decryptInfo) { - LOGV("deleting decryptInfo"); - delete decryptHandle->decryptInfo; decryptHandle->decryptInfo = NULL; - } - delete decryptHandle; decryptHandle = NULL; return reply.readInt32(); } diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk index f94f9a3..e3cd44f 100644 --- a/drm/drmserver/Android.mk +++ b/drm/drmserver/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES:= \ DrmManagerService.cpp LOCAL_SHARED_LIBRARIES := \ + libmedia \ libutils \ libbinder diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp index 1eee5f2..2fee59c 100644 --- a/drm/drmserver/DrmManager.cpp +++ b/drm/drmserver/DrmManager.cpp @@ -37,7 +37,6 @@ using namespace android; -Vector<int> DrmManager::mUniqueIdVector; const String8 DrmManager::EMPTY_STRING(""); DrmManager::DrmManager() : diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp index 0901a44..583669e 100644 --- a/drm/drmserver/DrmManagerService.cpp +++ b/drm/drmserver/DrmManagerService.cpp @@ -19,6 +19,7 @@ #include <utils/Log.h> #include <private/android_filesystem_config.h> +#include <media/MemoryLeakTrackUtil.h> #include <errno.h> #include <utils/threads.h> @@ -256,3 +257,31 @@ ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle, return mDrmManager->pread(uniqueId, decryptHandle, buffer, numBytes, offset); } +status_t DrmManagerService::dump(int fd, const Vector<String16>& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + snprintf(buffer, SIZE, "Permission Denial: " + "can't dump DrmManagerService from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + result.append(buffer); + } else { +#if DRM_MEMORY_LEAK_TRACK + bool dumpMem = false; + for (size_t i = 0; i < args.size(); i++) { + if (args[i] == String16("-m")) { + dumpMem = true; + } + } + if (dumpMem) { + dumpMemoryAddresses(fd); + } +#endif + } + write(fd, result.string(), result.size()); + return NO_ERROR; +} + diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java index 9f86f5f..2222ae8 100755 --- a/drm/java/android/drm/DrmInfoRequest.java +++ b/drm/java/android/drm/DrmInfoRequest.java @@ -26,7 +26,7 @@ import java.util.Iterator; * */ public class DrmInfoRequest { - // Changes in following constants should be in sync with DrmInfoRequest.cpp + // Changes in following constants should be in sync with DrmInfoRequest.h /** * Acquires DRM server registration information. */ diff --git a/drm/jni/Android.mk b/drm/jni/Android.mk index b65e4da..69bb48d 100644 --- a/drm/jni/Android.mk +++ b/drm/jni/Android.mk @@ -42,7 +42,7 @@ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/base/drm/libdrmframework/plugins/common/include \ $(TOP)/frameworks/base/include -LOCAL_PRELINK_MODULE := false + LOCAL_MODULE_TAGS := optional diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk index 99133ba..f1526a4 100644 --- a/drm/libdrmframework/Android.mk +++ b/drm/libdrmframework/Android.mk @@ -40,7 +40,7 @@ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/base/drm/libdrmframework/include \ $(TOP)/frameworks/base/include -LOCAL_PRELINK_MODULE := false + LOCAL_MODULE_TAGS := optional diff --git a/drm/libdrmframework/DrmManagerClient.cpp b/drm/libdrmframework/DrmManagerClient.cpp index c1f382a..b50199f 100644 --- a/drm/libdrmframework/DrmManagerClient.cpp +++ b/drm/libdrmframework/DrmManagerClient.cpp @@ -76,12 +76,13 @@ int DrmManagerClient::checkRightsStatus(const String8& path, int action) { return mDrmManagerClientImpl->checkRightsStatus(mUniqueId, path, action); } -status_t DrmManagerClient::consumeRights(DecryptHandle* decryptHandle, int action, bool reserve) { +status_t DrmManagerClient::consumeRights( + sp<DecryptHandle> &decryptHandle, int action, bool reserve) { return mDrmManagerClientImpl->consumeRights(mUniqueId, decryptHandle, action, reserve); } status_t DrmManagerClient::setPlaybackStatus( - DecryptHandle* decryptHandle, int playbackStatus, int64_t position) { + sp<DecryptHandle> &decryptHandle, int playbackStatus, int64_t position) { return mDrmManagerClientImpl ->setPlaybackStatus(mUniqueId, decryptHandle, playbackStatus, position); } @@ -115,37 +116,39 @@ status_t DrmManagerClient::getAllSupportInfo(int* length, DrmSupportInfo** drmSu return mDrmManagerClientImpl->getAllSupportInfo(mUniqueId, length, drmSupportInfoArray); } -DecryptHandle* DrmManagerClient::openDecryptSession(int fd, off64_t offset, off64_t length) { +sp<DecryptHandle> DrmManagerClient::openDecryptSession(int fd, off64_t offset, off64_t length) { return mDrmManagerClientImpl->openDecryptSession(mUniqueId, fd, offset, length); } -DecryptHandle* DrmManagerClient::openDecryptSession(const char* uri) { +sp<DecryptHandle> DrmManagerClient::openDecryptSession(const char* uri) { return mDrmManagerClientImpl->openDecryptSession(mUniqueId, uri); } -status_t DrmManagerClient::closeDecryptSession(DecryptHandle* decryptHandle) { +status_t DrmManagerClient::closeDecryptSession(sp<DecryptHandle> &decryptHandle) { return mDrmManagerClientImpl->closeDecryptSession(mUniqueId, decryptHandle); } status_t DrmManagerClient::initializeDecryptUnit( - DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) { + sp<DecryptHandle> &decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) { return mDrmManagerClientImpl->initializeDecryptUnit( mUniqueId, decryptHandle, decryptUnitId, headerInfo); } status_t DrmManagerClient::decrypt( - DecryptHandle* decryptHandle, int decryptUnitId, - const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) { + sp<DecryptHandle> &decryptHandle, int decryptUnitId, + const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) { return mDrmManagerClientImpl->decrypt( mUniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV); } -status_t DrmManagerClient::finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId) { - return mDrmManagerClientImpl->finalizeDecryptUnit(mUniqueId, decryptHandle, decryptUnitId); +status_t DrmManagerClient::finalizeDecryptUnit( + sp<DecryptHandle> &decryptHandle, int decryptUnitId) { + return mDrmManagerClientImpl->finalizeDecryptUnit(mUniqueId, + decryptHandle, decryptUnitId); } ssize_t DrmManagerClient::pread( - DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) { + sp<DecryptHandle> &decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) { return mDrmManagerClientImpl->pread(mUniqueId, decryptHandle, buffer, numBytes, offset); } diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp index 9c7fed3..a57dd98 100644 --- a/drm/libdrmframework/DrmManagerClientImpl.cpp +++ b/drm/libdrmframework/DrmManagerClientImpl.cpp @@ -81,14 +81,16 @@ void DrmManagerClientImpl::removeClient(int uniqueId) { } status_t DrmManagerClientImpl::setOnInfoListener( - int uniqueId, const sp<DrmManagerClient::OnInfoListener>& infoListener) { + int uniqueId, + const sp<DrmManagerClient::OnInfoListener>& infoListener) { Mutex::Autolock _l(mLock); mOnInfoListener = infoListener; return getDrmManagerService()->setDrmServiceListener(uniqueId, (NULL != infoListener.get()) ? this : NULL); } -status_t DrmManagerClientImpl::installDrmEngine(int uniqueId, const String8& drmEngineFile) { +status_t DrmManagerClientImpl::installDrmEngine( + int uniqueId, const String8& drmEngineFile) { status_t status = DRM_ERROR_UNKNOWN; if (EMPTY_STRING != drmEngineFile) { status = getDrmManagerService()->installDrmEngine(uniqueId, drmEngineFile); @@ -100,7 +102,8 @@ DrmConstraints* DrmManagerClientImpl::getConstraints( int uniqueId, const String8* path, const int action) { DrmConstraints *drmConstraints = NULL; if ((NULL != path) && (EMPTY_STRING != *path)) { - drmConstraints = getDrmManagerService()->getConstraints(uniqueId, path, action); + drmConstraints = + getDrmManagerService()->getConstraints(uniqueId, path, action); } return drmConstraints; } @@ -113,7 +116,8 @@ DrmMetadata* DrmManagerClientImpl::getMetadata(int uniqueId, const String8* path return drmMetadata; } -bool DrmManagerClientImpl::canHandle(int uniqueId, const String8& path, const String8& mimeType) { +bool DrmManagerClientImpl::canHandle( + int uniqueId, const String8& path, const String8& mimeType) { bool retCode = false; if ((EMPTY_STRING != path) || (EMPTY_STRING != mimeType)) { retCode = getDrmManagerService()->canHandle(uniqueId, path, mimeType); @@ -121,7 +125,8 @@ bool DrmManagerClientImpl::canHandle(int uniqueId, const String8& path, const St return retCode; } -DrmInfoStatus* DrmManagerClientImpl::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) { +DrmInfoStatus* DrmManagerClientImpl::processDrmInfo( + int uniqueId, const DrmInfo* drmInfo) { DrmInfoStatus *drmInfoStatus = NULL; if (NULL != drmInfo) { drmInfoStatus = getDrmManagerService()->processDrmInfo(uniqueId, drmInfo); @@ -129,7 +134,8 @@ DrmInfoStatus* DrmManagerClientImpl::processDrmInfo(int uniqueId, const DrmInfo* return drmInfoStatus; } -DrmInfo* DrmManagerClientImpl::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) { +DrmInfo* DrmManagerClientImpl::acquireDrmInfo( + int uniqueId, const DrmInfoRequest* drmInfoRequest) { DrmInfo* drmInfo = NULL; if (NULL != drmInfoRequest) { drmInfo = getDrmManagerService()->acquireDrmInfo(uniqueId, drmInfoRequest); @@ -140,13 +146,12 @@ DrmInfo* DrmManagerClientImpl::acquireDrmInfo(int uniqueId, const DrmInfoRequest status_t DrmManagerClientImpl::saveRights(int uniqueId, const DrmRights& drmRights, const String8& rightsPath, const String8& contentPath) { status_t status = DRM_ERROR_UNKNOWN; - if (EMPTY_STRING != contentPath) { - status = getDrmManagerService()->saveRights(uniqueId, drmRights, rightsPath, contentPath); - } - return status; + return getDrmManagerService()->saveRights( + uniqueId, drmRights, rightsPath, contentPath); } -String8 DrmManagerClientImpl::getOriginalMimeType(int uniqueId, const String8& path) { +String8 DrmManagerClientImpl::getOriginalMimeType( + int uniqueId, const String8& path) { String8 mimeType = EMPTY_STRING; if (EMPTY_STRING != path) { mimeType = getDrmManagerService()->getOriginalMimeType(uniqueId, path); @@ -158,7 +163,8 @@ int DrmManagerClientImpl::getDrmObjectType( int uniqueId, const String8& path, const String8& mimeType) { int drmOjectType = DrmObjectType::UNKNOWN; if ((EMPTY_STRING != path) || (EMPTY_STRING != mimeType)) { - drmOjectType = getDrmManagerService()->getDrmObjectType(uniqueId, path, mimeType); + drmOjectType = + getDrmManagerService()->getDrmObjectType(uniqueId, path, mimeType); } return drmOjectType; } @@ -167,35 +173,41 @@ int DrmManagerClientImpl::checkRightsStatus( int uniqueId, const String8& path, int action) { int rightsStatus = RightsStatus::RIGHTS_INVALID; if (EMPTY_STRING != path) { - rightsStatus = getDrmManagerService()->checkRightsStatus(uniqueId, path, action); + rightsStatus = + getDrmManagerService()->checkRightsStatus(uniqueId, path, action); } return rightsStatus; } status_t DrmManagerClientImpl::consumeRights( - int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) { + int uniqueId, sp<DecryptHandle> &decryptHandle, + int action, bool reserve) { status_t status = DRM_ERROR_UNKNOWN; - if (NULL != decryptHandle) { - status = getDrmManagerService()->consumeRights(uniqueId, decryptHandle, action, reserve); + if (NULL != decryptHandle.get()) { + status = getDrmManagerService()->consumeRights( + uniqueId, decryptHandle.get(), action, reserve); } return status; } status_t DrmManagerClientImpl::setPlaybackStatus( - int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) { + int uniqueId, sp<DecryptHandle> &decryptHandle, + int playbackStatus, int64_t position) { status_t status = DRM_ERROR_UNKNOWN; - if (NULL != decryptHandle) { + if (NULL != decryptHandle.get()) { status = getDrmManagerService()->setPlaybackStatus( - uniqueId, decryptHandle, playbackStatus, position); + uniqueId, decryptHandle.get(), playbackStatus, position); } return status; } bool DrmManagerClientImpl::validateAction( - int uniqueId, const String8& path, int action, const ActionDescription& description) { + int uniqueId, const String8& path, + int action, const ActionDescription& description) { bool retCode = false; if (EMPTY_STRING != path) { - retCode = getDrmManagerService()->validateAction(uniqueId, path, action, description); + retCode = getDrmManagerService()->validateAction( + uniqueId, path, action, description); } return retCode; } @@ -212,7 +224,8 @@ status_t DrmManagerClientImpl::removeAllRights(int uniqueId) { return getDrmManagerService()->removeAllRights(uniqueId); } -int DrmManagerClientImpl::openConvertSession(int uniqueId, const String8& mimeType) { +int DrmManagerClientImpl::openConvertSession( + int uniqueId, const String8& mimeType) { int retCode = INVALID_VALUE; if (EMPTY_STRING != mimeType) { retCode = getDrmManagerService()->openConvertSession(uniqueId, mimeType); @@ -224,12 +237,14 @@ DrmConvertedStatus* DrmManagerClientImpl::convertData( int uniqueId, int convertId, const DrmBuffer* inputData) { DrmConvertedStatus* drmConvertedStatus = NULL; if (NULL != inputData) { - drmConvertedStatus = getDrmManagerService()->convertData(uniqueId, convertId, inputData); + drmConvertedStatus = + getDrmManagerService()->convertData(uniqueId, convertId, inputData); } return drmConvertedStatus; } -DrmConvertedStatus* DrmManagerClientImpl::closeConvertSession(int uniqueId, int convertId) { +DrmConvertedStatus* DrmManagerClientImpl::closeConvertSession( + int uniqueId, int convertId) { return getDrmManagerService()->closeConvertSession(uniqueId, convertId); } @@ -237,17 +252,19 @@ status_t DrmManagerClientImpl::getAllSupportInfo( int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) { status_t status = DRM_ERROR_UNKNOWN; if ((NULL != drmSupportInfoArray) && (NULL != length)) { - status = getDrmManagerService()->getAllSupportInfo(uniqueId, length, drmSupportInfoArray); + status = getDrmManagerService()->getAllSupportInfo( + uniqueId, length, drmSupportInfoArray); } return status; } -DecryptHandle* DrmManagerClientImpl::openDecryptSession( +sp<DecryptHandle> DrmManagerClientImpl::openDecryptSession( int uniqueId, int fd, off64_t offset, off64_t length) { return getDrmManagerService()->openDecryptSession(uniqueId, fd, offset, length); } -DecryptHandle* DrmManagerClientImpl::openDecryptSession(int uniqueId, const char* uri) { +sp<DecryptHandle> DrmManagerClientImpl::openDecryptSession( + int uniqueId, const char* uri) { DecryptHandle* handle = NULL; if (NULL != uri) { handle = getDrmManagerService()->openDecryptSession(uniqueId, uri); @@ -255,50 +272,57 @@ DecryptHandle* DrmManagerClientImpl::openDecryptSession(int uniqueId, const char return handle; } -status_t DrmManagerClientImpl::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) { +status_t DrmManagerClientImpl::closeDecryptSession( + int uniqueId, sp<DecryptHandle> &decryptHandle) { status_t status = DRM_ERROR_UNKNOWN; - if (NULL != decryptHandle) { - status = getDrmManagerService()->closeDecryptSession( uniqueId, decryptHandle); + if (NULL != decryptHandle.get()) { + status = getDrmManagerService()->closeDecryptSession( + uniqueId, decryptHandle.get()); } return status; } -status_t DrmManagerClientImpl::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, - int decryptUnitId, const DrmBuffer* headerInfo) { +status_t DrmManagerClientImpl::initializeDecryptUnit( + int uniqueId, sp<DecryptHandle> &decryptHandle, + int decryptUnitId, const DrmBuffer* headerInfo) { status_t status = DRM_ERROR_UNKNOWN; - if ((NULL != decryptHandle) && (NULL != headerInfo)) { + if ((NULL != decryptHandle.get()) && (NULL != headerInfo)) { status = getDrmManagerService()->initializeDecryptUnit( - uniqueId, decryptHandle, decryptUnitId, headerInfo); + uniqueId, decryptHandle.get(), decryptUnitId, headerInfo); } return status; } -status_t DrmManagerClientImpl::decrypt(int uniqueId, DecryptHandle* decryptHandle, - int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) { +status_t DrmManagerClientImpl::decrypt( + int uniqueId, sp<DecryptHandle> &decryptHandle, + int decryptUnitId, const DrmBuffer* encBuffer, + DrmBuffer** decBuffer, DrmBuffer* IV) { status_t status = DRM_ERROR_UNKNOWN; - if ((NULL != decryptHandle) && (NULL != encBuffer) + if ((NULL != decryptHandle.get()) && (NULL != encBuffer) && (NULL != decBuffer) && (NULL != *decBuffer)) { status = getDrmManagerService()->decrypt( - uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV); + uniqueId, decryptHandle.get(), decryptUnitId, + encBuffer, decBuffer, IV); } return status; } status_t DrmManagerClientImpl::finalizeDecryptUnit( - int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) { + int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId) { status_t status = DRM_ERROR_UNKNOWN; - if (NULL != decryptHandle) { - status - = getDrmManagerService()->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId); + if (NULL != decryptHandle.get()) { + status = getDrmManagerService()->finalizeDecryptUnit( + uniqueId, decryptHandle.get(), decryptUnitId); } return status; } -ssize_t DrmManagerClientImpl::pread(int uniqueId, DecryptHandle* decryptHandle, +ssize_t DrmManagerClientImpl::pread(int uniqueId, sp<DecryptHandle> &decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) { ssize_t retCode = INVALID_VALUE; - if ((NULL != decryptHandle) && (NULL != buffer) && (0 < numBytes)) { - retCode = getDrmManagerService()->pread(uniqueId, decryptHandle, buffer, numBytes, offset); + if ((NULL != decryptHandle.get()) && (NULL != buffer) && (0 < numBytes)) { + retCode = getDrmManagerService()->pread( + uniqueId, decryptHandle.get(), buffer, numBytes, offset); } return retCode; } diff --git a/drm/libdrmframework/include/DrmManager.h b/drm/libdrmframework/include/DrmManager.h index c7276f9..af2c2a8 100644 --- a/drm/libdrmframework/include/DrmManager.h +++ b/drm/libdrmframework/include/DrmManager.h @@ -30,7 +30,6 @@ class IDrmManager; class DrmRegistrationInfo; class DrmUnregistrationInfo; class DrmRightsAcquisitionInfo; -class DrmContentIds; class DrmConstraints; class DrmMetadata; class DrmRights; @@ -141,7 +140,7 @@ private: bool canHandle(int uniqueId, const String8& path); private: - static Vector<int> mUniqueIdVector; + Vector<int> mUniqueIdVector; static const String8 EMPTY_STRING; int mDecryptSessionId; diff --git a/drm/libdrmframework/include/DrmManagerClientImpl.h b/drm/libdrmframework/include/DrmManagerClientImpl.h index 429e4c3..564896b 100644 --- a/drm/libdrmframework/include/DrmManagerClientImpl.h +++ b/drm/libdrmframework/include/DrmManagerClientImpl.h @@ -189,7 +189,7 @@ public: * @return status_t * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ - status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve); + status_t consumeRights(int uniqueId, sp<DecryptHandle> &decryptHandle, int action, bool reserve); /** * Informs the DRM engine about the playback actions performed on the DRM files. @@ -203,7 +203,7 @@ public: * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ status_t setPlaybackStatus( - int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position); + int uniqueId, sp<DecryptHandle> &decryptHandle, int playbackStatus, int64_t position); /** * Validates whether an action on the DRM content is allowed or not. @@ -303,7 +303,7 @@ public: * @return * Handle for the decryption session */ - DecryptHandle* openDecryptSession(int uniqueId, int fd, off64_t offset, off64_t length); + sp<DecryptHandle> openDecryptSession(int uniqueId, int fd, off64_t offset, off64_t length); /** * Open the decrypt session to decrypt the given protected content @@ -313,7 +313,7 @@ public: * @return * Handle for the decryption session */ - DecryptHandle* openDecryptSession(int uniqueId, const char* uri); + sp<DecryptHandle> openDecryptSession(int uniqueId, const char* uri); /** * Close the decrypt session for the given handle @@ -323,7 +323,7 @@ public: * @return status_t * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ - status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle); + status_t closeDecryptSession(int uniqueId, sp<DecryptHandle> &decryptHandle); /** * Initialize decryption for the given unit of the protected content @@ -335,7 +335,7 @@ public: * @return status_t * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ - status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, + status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo); /** @@ -355,7 +355,7 @@ public: * DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED, * DRM_ERROR_DECRYPT for failure. */ - status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, + status_t decrypt(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV); /** @@ -367,7 +367,7 @@ public: * @return status_t * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ - status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId); + status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId); /** * Reads the specified number of bytes from an open DRM file. @@ -380,7 +380,7 @@ public: * * @return Number of bytes read. Returns -1 for Failure. */ - ssize_t pread(int uniqueId, DecryptHandle* decryptHandle, + ssize_t pread(int uniqueId, sp<DecryptHandle> &decryptHandle, void* buffer, ssize_t numBytes, off64_t offset); /** diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/libdrmframework/include/DrmManagerService.h index d0a0db7..227496a 100644 --- a/drm/libdrmframework/include/DrmManagerService.h +++ b/drm/libdrmframework/include/DrmManagerService.h @@ -115,6 +115,8 @@ public: ssize_t pread(int uniqueId, DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset); + virtual status_t dump(int fd, const Vector<String16>& args); + private: DrmManager* mDrmManager; }; diff --git a/drm/libdrmframework/include/IDrmManagerService.h b/drm/libdrmframework/include/IDrmManagerService.h index 2424ea5..7727e55 100644 --- a/drm/libdrmframework/include/IDrmManagerService.h +++ b/drm/libdrmframework/include/IDrmManagerService.h @@ -25,7 +25,6 @@ namespace android { -class DrmContentIds; class DrmConstraints; class DrmMetadata; class DrmRights; diff --git a/drm/libdrmframework/plugins/common/include/IDrmEngine.h b/drm/libdrmframework/plugins/common/include/IDrmEngine.h index d05c24f..77460f6 100644 --- a/drm/libdrmframework/plugins/common/include/IDrmEngine.h +++ b/drm/libdrmframework/plugins/common/include/IDrmEngine.h @@ -21,7 +21,6 @@ namespace android { -class DrmContentIds; class DrmConstraints; class DrmMetadata; class DrmRights; diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk index af67aa3..9805a40 100644 --- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk +++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk @@ -47,7 +47,7 @@ LOCAL_STATIC_LIBRARIES := \ libfwdlock-converter \ libfwdlock-decoder -LOCAL_PRELINK_MODULE := false + LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ diff --git a/drm/libdrmframework/plugins/passthru/Android.mk b/drm/libdrmframework/plugins/passthru/Android.mk index 7856d37..be18b64 100644 --- a/drm/libdrmframework/plugins/passthru/Android.mk +++ b/drm/libdrmframework/plugins/passthru/Android.mk @@ -32,7 +32,7 @@ else LOCAL_SHARED_LIBRARIES += libdl endif -LOCAL_PRELINK_MODULE := false + LOCAL_C_INCLUDES += \ $(TOP)/frameworks/base/drm/libdrmframework/include \ diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 965abe9..e493b18 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -1330,6 +1330,29 @@ public class Canvas { } /** + * Draw the glyphs, with origin at (x,y), using the specified paint. The + * origin is interpreted based on the Align setting in the paint. + * + * @param glyphs The glyphs to be drawn + * @param x The x-coordinate of the origin of the text being drawn + * @param y The y-coordinate of the origin of the text being drawn + * @param paint The paint used for the text (e.g. color, size, style) + * + * @hide + * + * Used only for BiDi / RTL Tests + */ + public void drawGlyphs(char[] glyphs, int index, int count, float x, float y, + Paint paint) { + if ((index | count | (index + count) | + (glyphs.length - index - count)) < 0) { + throw new IndexOutOfBoundsException(); + } + native_drawGlyphs(mNativeCanvas, glyphs, index, count, x, y, paint.mBidiFlags, + paint.mNativePaint); + } + + /** * Draw the text, with origin at (x,y), using the specified paint. The * origin is interpreted based on the Align setting in the paint. * @@ -1722,7 +1745,9 @@ public class Canvas { private static native void native_drawText(int nativeCanvas, String text, int start, int end, float x, float y, int flags, int paint); - + private static native void native_drawGlyphs(int nativeCanvas, char[] glyphs, + int index, int count, float x, + float y, int flags, int paint); private static native void native_drawTextRun(int nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, float x, float y, int flags, int paint); diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 0a23bae..96eb936 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1455,6 +1455,43 @@ public class Paint { } /** + * Return the glypth Ids for the characters in the string. + * + * @param text The text to measure + * @param start The index of the first char to to measure + * @param end The end of the text slice to measure + * @param contextStart the index of the first character to use for shaping context, + * must be <= start + * @param contextEnd the index past the last character to use for shaping context, + * must be >= end + * @param flags the flags to control the advances, either {@link #DIRECTION_LTR} + * or {@link #DIRECTION_RTL} + * @param glyphs array to receive the glyph Ids of the characters. + * Must be at least a large as the text. + * @return the number of glyphs in the returned array + * + * @hide + * + * Used only for BiDi / RTL Tests + */ + public int getTextGlypths(String text, int start, int end, int contextStart, int contextEnd, + int flags, char[] glyphs) { + if ((start | end | contextStart | contextEnd | (end - start) + | (start - contextStart) | (contextEnd - end) | (text.length() - end) + | (text.length() - contextEnd)) < 0) { + throw new IndexOutOfBoundsException(); + } + if (end - start > glyphs.length) { + throw new ArrayIndexOutOfBoundsException(); + } + if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) { + throw new IllegalArgumentException("unknown flags value: " + flags); + } + return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd, + flags, glyphs); + } + + /** * Convenience overload that takes a char array instead of a * String. * @@ -1859,6 +1896,10 @@ public class Paint { private static native int native_getTextWidths(int native_object, String text, int start, int end, float[] widths); + private static native int native_getTextGlyphs(int native_object, + String text, int start, int end, int contextStart, int contextEnd, + int flags, char[] glyphs); + private static native float native_getTextRunAdvances(int native_object, char[] text, int index, int count, int contextIndex, int contextCount, int flags, float[] advances, int advancesIndex); diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index 970b207..cfae0c1 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -144,6 +144,20 @@ public class SurfaceTexture { nativeGetTransformMatrix(mtx); } + /** + * Retrieve the timestamp associated with the texture image set by the most recent call to + * updateTexImage. + * + * This timestamp is in nanoseconds, and is guaranteed to be monotonically increasing. The + * specific meaning and zero point of the timestamp depends on the source providing images to + * the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot + * generally be compared across SurfaceTexture instances, or across multiple program + * invocations. It is mostly useful for determining time offsets between subsequent frames. + */ + public long getTimestamp() { + return nativeGetTimestamp(); + } + protected void finalize() throws Throwable { try { nativeFinalize(); @@ -182,6 +196,7 @@ public class SurfaceTexture { private native void nativeInit(int texName, Object weakSelf); private native void nativeFinalize(); private native void nativeGetTransformMatrix(float[] mtx); + private native long nativeGetTimestamp(); private native void nativeUpdateTexImage(); /* diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 2c09ddc..22fbdf9 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -88,6 +88,7 @@ public class BitmapDrawable extends Drawable { * Create an empty drawable, setting initial target density based on * the display metrics of the resources. */ + @SuppressWarnings({"UnusedParameters"}) public BitmapDrawable(Resources res) { mBitmapState = new BitmapState((Bitmap) null); mBitmapState.mTargetDensity = mTargetDensity; @@ -128,6 +129,7 @@ public class BitmapDrawable extends Drawable { /** * Create a drawable by opening a given file path and decoding the bitmap. */ + @SuppressWarnings({"UnusedParameters"}) public BitmapDrawable(Resources res, String filepath) { this(new BitmapState(BitmapFactory.decodeFile(filepath)), null); mBitmapState.mTargetDensity = mTargetDensity; @@ -152,6 +154,7 @@ public class BitmapDrawable extends Drawable { /** * Create a drawable by decoding a bitmap from the given input stream. */ + @SuppressWarnings({"UnusedParameters"}) public BitmapDrawable(Resources res, java.io.InputStream is) { this(new BitmapState(BitmapFactory.decodeStream(is)), null); mBitmapState.mTargetDensity = mTargetDensity; @@ -160,10 +163,16 @@ public class BitmapDrawable extends Drawable { } } + /** + * Returns the paint used to render this drawable. + */ public final Paint getPaint() { return mBitmapState.mPaint; } - + + /** + * Returns the bitmap used by this drawable to render. May be null. + */ public final Bitmap getBitmap() { return mBitmap; } @@ -249,6 +258,12 @@ public class BitmapDrawable extends Drawable { } } + /** + * Enables or disables anti-aliasing for this drawable. Anti-aliasing affects + * the edges of the bitmap only so it applies only when the drawable is rotated. + * + * @param aa True if the bitmap should be anti-aliased, false otherwise. + */ public void setAntiAlias(boolean aa) { mBitmapState.mPaint.setAntiAlias(aa); invalidateSelf(); @@ -266,26 +281,71 @@ public class BitmapDrawable extends Drawable { invalidateSelf(); } + /** + * Indicates the repeat behavior of this drawable on the X axis. + * + * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat, + * {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise. + */ public Shader.TileMode getTileModeX() { return mBitmapState.mTileModeX; } + /** + * Indicates the repeat behavior of this drawable on the Y axis. + * + * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat, + * {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise. + */ public Shader.TileMode getTileModeY() { return mBitmapState.mTileModeY; } + /** + * Sets the repeat behavior of this drawable on the X axis. By default, the drawable + * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or + * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap + * is smaller than this drawable. + * + * @param mode The repeat mode for this drawable. + * + * @see #setTileModeY(android.graphics.Shader.TileMode) + * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode) + */ public void setTileModeX(Shader.TileMode mode) { setTileModeXY(mode, mBitmapState.mTileModeY); } + /** + * Sets the repeat behavior of this drawable on the Y axis. By default, the drawable + * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or + * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap + * is smaller than this drawable. + * + * @param mode The repeat mode for this drawable. + * + * @see #setTileModeX(android.graphics.Shader.TileMode) + * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode) + */ public final void setTileModeY(Shader.TileMode mode) { setTileModeXY(mBitmapState.mTileModeX, mode); } + /** + * Sets the repeat behavior of this drawable on both axis. By default, the drawable + * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or + * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap + * is smaller than this drawable. + * + * @param xmode The X repeat mode for this drawable. + * @param ymode The Y repeat mode for this drawable. + * + * @see #setTileModeX(android.graphics.Shader.TileMode) + * @see #setTileModeY(android.graphics.Shader.TileMode) + */ public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) { final BitmapState state = mBitmapState; - if (state.mPaint.getShader() == null || - state.mTileModeX != xmode || state.mTileModeY != ymode) { + if (state.mTileModeX != xmode || state.mTileModeY != ymode) { state.mTileModeX = xmode; state.mTileModeY = ymode; mRebuildShader = true; @@ -316,10 +376,9 @@ public class BitmapDrawable extends Drawable { if (tmx == null && tmy == null) { state.mPaint.setShader(null); } else { - Shader s = new BitmapShader(bitmap, + state.mPaint.setShader(new BitmapShader(bitmap, tmx == null ? Shader.TileMode.CLAMP : tmx, - tmy == null ? Shader.TileMode.CLAMP : tmy); - state.mPaint.setShader(s); + tmy == null ? Shader.TileMode.CLAMP : tmy)); } mRebuildShader = false; copyBounds(mDstRect); @@ -335,7 +394,7 @@ public class BitmapDrawable extends Drawable { canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint); } else { if (mApplyGravity) { - mDstRect.set(getBounds()); + copyBounds(mDstRect); mApplyGravity = false; } canvas.drawRect(mDstRect, state.mPaint); @@ -365,6 +424,7 @@ public class BitmapDrawable extends Drawable { public Drawable mutate() { if (!mMutated && super.mutate() == this) { mBitmapState = new BitmapState(mBitmapState); + mRebuildShader = true; mMutated = true; } return this; @@ -448,8 +508,8 @@ public class BitmapDrawable extends Drawable { int mChangingConfigurations; int mGravity = Gravity.FILL; Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS); - Shader.TileMode mTileModeX; - Shader.TileMode mTileModeY; + Shader.TileMode mTileModeX = null; + Shader.TileMode mTileModeY = null; int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; BitmapState(Bitmap bitmap) { @@ -491,6 +551,6 @@ public class BitmapDrawable extends Drawable { } else { mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; } - setBitmap(state.mBitmap); + setBitmap(state != null ? state.mBitmap : null); } } diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java index 669beac..8ce1d9a 100644 --- a/graphics/java/android/renderscript/BaseObj.java +++ b/graphics/java/android/renderscript/BaseObj.java @@ -75,11 +75,17 @@ class BaseObj { * @param name The name to assign to the object. */ public void setName(String name) { + if (name == null) { + throw new RSIllegalArgumentException( + "setName requires a string of non-zero length."); + } if(name.length() < 1) { - throw new RSIllegalArgumentException("setName does not accept a zero length string."); + throw new RSIllegalArgumentException( + "setName does not accept a zero length string."); } if(mName != null) { - throw new RSIllegalArgumentException("setName object already has a name."); + throw new RSIllegalArgumentException( + "setName object already has a name."); } try { @@ -106,9 +112,9 @@ class BaseObj { } /** - * destroy disconnects the object from the native object effectivly + * destroy disconnects the object from the native object effectively * rendering this java object dead. The primary use is to force immediate - * cleanup of resources when its believed the GC will not respond quickly + * cleanup of resources when it is believed the GC will not respond quickly * enough. */ synchronized public void destroy() { diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index b51279a..f577532 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -457,20 +457,11 @@ public class RenderScript { rsnScriptSetVarObj(mContext, id, slot, val); } - native void rsnScriptCBegin(int con); - synchronized void nScriptCBegin() { + native int rsnScriptCCreate(int con, String resName, String cacheDir, + byte[] script, int length); + synchronized int nScriptCCreate(String resName, String cacheDir, byte[] script, int length) { validate(); - rsnScriptCBegin(mContext); - } - native void rsnScriptCSetScript(int con, byte[] script, int offset, int length); - synchronized void nScriptCSetScript(byte[] script, int offset, int length) { - validate(); - rsnScriptCSetScript(mContext, script, offset, length); - } - native int rsnScriptCCreate(int con, String packageName, String resName, String cacheDir); - synchronized int nScriptCCreate(String packageName, String resName, String cacheDir) { - validate(); - return rsnScriptCCreate(mContext, packageName, resName, cacheDir); + return rsnScriptCCreate(mContext, resName, cacheDir, script, length); } native void rsnSamplerBegin(int con); diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java index 9445283..f865753 100644 --- a/graphics/java/android/renderscript/ScriptC.java +++ b/graphics/java/android/renderscript/ScriptC.java @@ -92,16 +92,13 @@ public class ScriptC extends Script { throw new Resources.NotFoundException(); } - rs.nScriptCBegin(); - rs.nScriptCSetScript(pgm, 0, pgmLength); - // E.g, /system/apps/Fountain.apk - String packageName = rs.getApplicationContext().getPackageResourcePath(); + //String packageName = rs.getApplicationContext().getPackageResourcePath(); // For res/raw/fountain.bc, it wil be /com.android.fountain:raw/fountain String resName = resources.getResourceName(resourceID); String cacheDir = rs.getApplicationContext().getCacheDir().toString(); Log.v(TAG, "Create script for resource = " + resName); - return rs.nScriptCCreate(packageName, resName, cacheDir); + return rs.nScriptCCreate(resName, cacheDir, pgm, pgmLength); } } diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk index 4c4a128..084f54a 100644 --- a/graphics/jni/Android.mk +++ b/graphics/jni/Android.mk @@ -19,7 +19,7 @@ LOCAL_SHARED_LIBRARIES := \ libskia \ libutils \ libui \ - libsurfaceflinger_client + libgui LOCAL_STATIC_LIBRARIES := diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index 2afd74c..c7f4809 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -848,65 +848,51 @@ nScriptInvokeV(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slo // ----------------------------------- -static void -nScriptCBegin(JNIEnv *_env, jobject _this, RsContext con) +static jint +nScriptCCreate(JNIEnv *_env, jobject _this, RsContext con, + jstring resName, jstring cacheDir, + jbyteArray scriptRef, jint length) { - LOG_API("nScriptCBegin, con(%p)", con); - rsScriptCBegin(con); -} + LOG_API("nScriptCCreate, con(%p)", con); + + AutoJavaStringToUTF8 resNameUTF(_env, resName); + AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir); + jint ret = 0; -static void -nScriptCSetScript(JNIEnv *_env, jobject _this, RsContext con, jbyteArray scriptRef, - jint offset, jint length) -{ - LOG_API("!!! nScriptCSetScript, con(%p)", con); jint _exception = 0; jint remaining; - jbyte* script_base = 0; jbyte* script_ptr; if (!scriptRef) { _exception = 1; //_env->ThrowNew(IAEClass, "script == null"); goto exit; } - if (offset < 0) { - _exception = 1; - //_env->ThrowNew(IAEClass, "offset < 0"); - goto exit; - } if (length < 0) { _exception = 1; //_env->ThrowNew(IAEClass, "length < 0"); goto exit; } - remaining = _env->GetArrayLength(scriptRef) - offset; + remaining = _env->GetArrayLength(scriptRef); if (remaining < length) { _exception = 1; //_env->ThrowNew(IAEClass, "length > script.length - offset"); goto exit; } - script_base = (jbyte *) + script_ptr = (jbyte *) _env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0); - script_ptr = script_base + offset; - rsScriptCSetText(con, (const char *)script_ptr, length); + //rsScriptCSetText(con, (const char *)script_ptr, length); + + ret = (jint)rsScriptCCreate(con, resNameUTF.c_str(), cacheDirUTF.c_str(), + (const char *)script_ptr, length); exit: - if (script_base) { - _env->ReleasePrimitiveArrayCritical(scriptRef, script_base, + if (script_ptr) { + _env->ReleasePrimitiveArrayCritical(scriptRef, script_ptr, _exception ? JNI_ABORT: 0); } -} -static jint -nScriptCCreate(JNIEnv *_env, jobject _this, RsContext con, jstring packageName, jstring resName, jstring cacheDir) -{ - LOG_API("nScriptCCreate, con(%p)", con); - AutoJavaStringToUTF8 packageNameUTF(_env, packageName); - AutoJavaStringToUTF8 resNameUTF(_env, resName); - AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir); - jint i = (jint)rsScriptCCreate(con, packageNameUTF.c_str(), resNameUTF.c_str(), cacheDirUTF.c_str()); - return i; + return ret; } // --------------------------------------------------------------------------- @@ -1282,9 +1268,7 @@ static JNINativeMethod methods[] = { {"rsnScriptSetVarV", "(III[B)V", (void*)nScriptSetVarV }, {"rsnScriptSetVarObj", "(IIII)V", (void*)nScriptSetVarObj }, -{"rsnScriptCBegin", "(I)V", (void*)nScriptCBegin }, -{"rsnScriptCSetScript", "(I[BII)V", (void*)nScriptCSetScript }, -{"rsnScriptCCreate", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", (void*)nScriptCCreate }, +{"rsnScriptCCreate", "(ILjava/lang/String;Ljava/lang/String;[BI)I", (void*)nScriptCCreate }, {"rsnProgramStoreBegin", "(III)V", (void*)nProgramStoreBegin }, {"rsnProgramStoreDepthFunc", "(II)V", (void*)nProgramStoreDepthFunc }, diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h index add33d3..dfca228 100644 --- a/include/drm/DrmInfoEvent.h +++ b/include/drm/DrmInfoEvent.h @@ -77,7 +77,7 @@ public: * @param[in] infoType Type of information * @param[in] message Message description */ - DrmInfoEvent(int uniqueId, int infoType, const String8& message); + DrmInfoEvent(int uniqueId, int infoType, const String8 message); /** * Destructor for DrmInfoEvent @@ -104,12 +104,12 @@ public: * * @return Message description */ - const String8& getMessage() const; + const String8 getMessage() const; private: int mUniqueId; int mInfoType; - const String8& mMessage; + const String8 mMessage; }; }; diff --git a/include/drm/DrmManagerClient.h b/include/drm/DrmManagerClient.h index 7a0bf4f..b8fe46d 100644 --- a/include/drm/DrmManagerClient.h +++ b/include/drm/DrmManagerClient.h @@ -69,7 +69,7 @@ public: * @return * Handle for the decryption session */ - DecryptHandle* openDecryptSession(int fd, off64_t offset, off64_t length); + sp<DecryptHandle> openDecryptSession(int fd, off64_t offset, off64_t length); /** * Open the decrypt session to decrypt the given protected content @@ -78,7 +78,7 @@ public: * @return * Handle for the decryption session */ - DecryptHandle* openDecryptSession(const char* uri); + sp<DecryptHandle> openDecryptSession(const char* uri); /** * Close the decrypt session for the given handle @@ -87,7 +87,7 @@ public: * @return status_t * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ - status_t closeDecryptSession(DecryptHandle* decryptHandle); + status_t closeDecryptSession(sp<DecryptHandle> &decryptHandle); /** * Consumes the rights for a content. @@ -101,7 +101,7 @@ public: * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure. * In case license has been expired, DRM_ERROR_LICENSE_EXPIRED will be returned. */ - status_t consumeRights(DecryptHandle* decryptHandle, int action, bool reserve); + status_t consumeRights(sp<DecryptHandle> &decryptHandle, int action, bool reserve); /** * Informs the DRM engine about the playback actions performed on the DRM files. @@ -113,7 +113,8 @@ public: * @return status_t * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ - status_t setPlaybackStatus(DecryptHandle* decryptHandle, int playbackStatus, int64_t position); + status_t setPlaybackStatus( + sp<DecryptHandle> &decryptHandle, int playbackStatus, int64_t position); /** * Initialize decryption for the given unit of the protected content @@ -125,7 +126,7 @@ public: * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ status_t initializeDecryptUnit( - DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo); + sp<DecryptHandle> &decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo); /** * Decrypt the protected content buffers for the given unit @@ -144,7 +145,7 @@ public: * DRM_ERROR_DECRYPT for failure. */ status_t decrypt( - DecryptHandle* decryptHandle, int decryptUnitId, + sp<DecryptHandle> &decryptHandle, int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV = NULL); /** @@ -155,7 +156,8 @@ public: * @return status_t * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure */ - status_t finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId); + status_t finalizeDecryptUnit( + sp<DecryptHandle> &decryptHandle, int decryptUnitId); /** * Reads the specified number of bytes from an open DRM file. @@ -167,7 +169,8 @@ public: * * @return Number of bytes read. Returns -1 for Failure. */ - ssize_t pread(DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset); + ssize_t pread(sp<DecryptHandle> &decryptHandle, + void* buffer, ssize_t numBytes, off64_t offset); /** * Validates whether an action on the DRM content is allowed or not. diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h index 454fc99..d2d1d7e 100644 --- a/include/drm/drm_framework_common.h +++ b/include/drm/drm_framework_common.h @@ -19,6 +19,7 @@ #include <utils/Vector.h> #include <utils/KeyedVector.h> +#include <utils/RefBase.h> #include <utils/String8.h> #include <utils/Errors.h> @@ -251,7 +252,7 @@ public: /** * Defines decryption handle */ -class DecryptHandle { +class DecryptHandle : public RefBase { public: /** * Decryption session Handle @@ -307,10 +308,15 @@ public: decryptId(INVALID_VALUE), mimeType(""), decryptApiType(INVALID_VALUE), - status(INVALID_VALUE) { + status(INVALID_VALUE), + decryptInfo(NULL) { } + ~DecryptHandle() { + delete decryptInfo; decryptInfo = NULL; + } + bool operator<(const DecryptHandle& handle) const { return (decryptId < handle.decryptId); } diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h index 168310c..6ed3c6f 100644 --- a/include/gui/ISurfaceTexture.h +++ b/include/gui/ISurfaceTexture.h @@ -62,8 +62,11 @@ public: // contents of the buffer associated with slot and transfers ownership of // that slot back to the server. It is not valid to call queueBuffer on a // slot that is not owned by the client or one for which a buffer associated - // via requestBuffer. - virtual status_t queueBuffer(int slot) = 0; + // via requestBuffer. In addition, a timestamp must be provided by the + // client for this buffer. The timestamp is measured in nanoseconds, and + // must be monotonically increasing. Its other properties (zero point, etc) + // are client-dependent, and should be documented by the client. + virtual status_t queueBuffer(int slot, int64_t timestamp) = 0; // cancelBuffer indicates that the client does not wish to fill in the // buffer associated with slot and transfers ownership of the slot back to diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 9bf38f7..afa64d3 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -66,7 +66,12 @@ public: // unmodified. virtual status_t dequeueBuffer(int *buf); - virtual status_t queueBuffer(int buf); + // queueBuffer returns a filled buffer to the SurfaceTexture. In addition, a + // timestamp must be provided for the buffer. The timestamp is in + // nanoseconds, and must be monotonically increasing. Its other semantics + // (zero point, etc) are client-dependent and should be documented by the + // client. + virtual status_t queueBuffer(int buf, int64_t timestamp); virtual void cancelBuffer(int buf); virtual status_t setCrop(const Rect& reg); virtual status_t setTransform(uint32_t transform); @@ -98,6 +103,14 @@ public: // functions. void getTransformMatrix(float mtx[16]); + // getTimestamp retrieves the timestamp associated with the texture image + // set by the most recent call to updateTexImage. + // + // The timestamp is in nanoseconds, and is monotonically increasing. Its + // other semantics (zero point, etc) are source-dependent and should be + // documented by the source. + int64_t getTimestamp(); + // setFrameAvailableListener sets the listener object that will be notified // when a new frame becomes available. void setFrameAvailableListener(const sp<FrameAvailableListener>& l); @@ -172,6 +185,10 @@ private: // gets set to mLastQueuedTransform each time updateTexImage is called. uint32_t mCurrentTransform; + // mCurrentTimestamp is the timestamp for the current texture. It + // gets set to mLastQueuedTimestamp each time updateTexImage is called. + int64_t mCurrentTimestamp; + // mLastQueued is the buffer slot index of the most recently enqueued buffer. // At construction time it is initialized to INVALID_BUFFER_SLOT, and is // updated each time queueBuffer is called. @@ -187,6 +204,10 @@ private: // queueBuffer gets called. uint32_t mLastQueuedTransform; + // mLastQueuedTimestamp is the timestamp for the buffer that was most + // recently queued. This gets set by queueBuffer. + int64_t mLastQueuedTimestamp; + // mNextCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. Rect mNextCrop; diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h index 7992105..df82bf2 100644 --- a/include/gui/SurfaceTextureClient.h +++ b/include/gui/SurfaceTextureClient.h @@ -63,6 +63,7 @@ private: int dispatchSetBufferCount(va_list args); int dispatchSetBuffersGeometry(va_list args); int dispatchSetBuffersTransform(va_list args); + int dispatchSetBuffersTimestamp(va_list args); int dispatchSetCrop(va_list args); int dispatchSetUsage(va_list args); @@ -71,6 +72,7 @@ private: int setBufferCount(int bufferCount); int setBuffersGeometry(int w, int h, int format); int setBuffersTransform(int transform); + int setBuffersTimestamp(int64_t timestamp); int setCrop(Rect const* rect); int setUsage(uint32_t reqUsage); @@ -114,6 +116,11 @@ private: // at the next deuque operation. It is initialized to 0. uint32_t mReqUsage; + // mTimestamp is the timestamp that will be used for the next buffer queue + // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that + // a timestamp is auto-generated when queueBuffer is called. + int64_t mTimestamp; + // mMutex is the mutex used to prevent concurrent access to the member // variables of SurfaceTexture objects. It must be locked whenever the // member variables are accessed. diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h index 8e3cdbb..1c1c268 100644 --- a/include/media/IMediaMetadataRetriever.h +++ b/include/media/IMediaMetadataRetriever.h @@ -18,10 +18,11 @@ #ifndef ANDROID_IMEDIAMETADATARETRIEVER_H #define ANDROID_IMEDIAMETADATARETRIEVER_H -#include <utils/RefBase.h> #include <binder/IInterface.h> #include <binder/Parcel.h> #include <binder/IMemory.h> +#include <utils/KeyedVector.h> +#include <utils/RefBase.h> namespace android { @@ -30,7 +31,11 @@ class IMediaMetadataRetriever: public IInterface public: DECLARE_META_INTERFACE(MediaMetadataRetriever); virtual void disconnect() = 0; - virtual status_t setDataSource(const char* srcUrl) = 0; + + virtual status_t setDataSource( + const char *srcUrl, + const KeyedVector<String8, String8> *headers = NULL) = 0; + virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0; virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option) = 0; virtual sp<IMemory> extractAlbumArt() = 0; diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h index 0449122..27b7e4d 100644 --- a/include/media/MediaMetadataRetrieverInterface.h +++ b/include/media/MediaMetadataRetrieverInterface.h @@ -30,7 +30,11 @@ class MediaMetadataRetrieverBase : public RefBase public: MediaMetadataRetrieverBase() {} virtual ~MediaMetadataRetrieverBase() {} - virtual status_t setDataSource(const char *url) = 0; + + virtual status_t setDataSource( + const char *url, + const KeyedVector<String8, String8> *headers = NULL) = 0; + virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0; virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) = 0; virtual MediaAlbumArt* extractAlbumArt() = 0; diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h new file mode 100644 index 0000000..290b748 --- /dev/null +++ b/include/media/MemoryLeakTrackUtil.h @@ -0,0 +1,28 @@ + +/* + * 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. + */ +#ifndef MEMORY_LEAK_TRACK_UTIL_H +#define MEMORY_LEAK_TRACK_UTIL_H + +namespace android { +/* + * Dump the memory adddress of the calling process to the given fd. + */ +extern void dumpMemoryAddresses(int fd); + +}; + +#endif // MEMORY_LEAK_TRACK_UTIL_H diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h index e905006..3e343e0 100644 --- a/include/media/mediametadataretriever.h +++ b/include/media/mediametadataretriever.h @@ -47,6 +47,12 @@ enum { METADATA_KEY_ALBUMARTIST = 13, METADATA_KEY_DISC_NUMBER = 14, METADATA_KEY_COMPILATION = 15, + METADATA_KEY_HAS_AUDIO = 16, + METADATA_KEY_HAS_VIDEO = 17, + METADATA_KEY_VIDEO_WIDTH = 18, + METADATA_KEY_VIDEO_HEIGHT = 19, + METADATA_KEY_BITRATE = 20, + // Add more here... }; @@ -56,7 +62,11 @@ public: MediaMetadataRetriever(); ~MediaMetadataRetriever(); void disconnect(); - status_t setDataSource(const char* dataSourceUrl); + + status_t setDataSource( + const char *dataSourceUrl, + const KeyedVector<String8, String8> *headers = NULL); + status_t setDataSource(int fd, int64_t offset, int64_t length); sp<IMemory> getFrameAtTime(int64_t timeUs, int option); sp<IMemory> extractAlbumArt(); diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h index a710546..67d940b 100644 --- a/include/media/mediarecorder.h +++ b/include/media/mediarecorder.h @@ -104,35 +104,62 @@ enum video_encoder { }; /* - * The state machine of the media_recorder uses a set of different state names. - * The mapping between the media_recorder and the pvauthorengine is shown below: - * - * mediarecorder pvauthorengine - * ---------------------------------------------------------------- - * MEDIA_RECORDER_ERROR ERROR - * MEDIA_RECORDER_IDLE IDLE - * MEDIA_RECORDER_INITIALIZED OPENED - * MEDIA_RECORDER_DATASOURCE_CONFIGURED - * MEDIA_RECORDER_PREPARED INITIALIZED - * MEDIA_RECORDER_RECORDING RECORDING + * The state machine of the media_recorder. */ enum media_recorder_states { + // Error state. MEDIA_RECORDER_ERROR = 0, + + // Recorder was just created. MEDIA_RECORDER_IDLE = 1 << 0, + + // Recorder has been initialized. MEDIA_RECORDER_INITIALIZED = 1 << 1, + + // Configuration of the recorder has been completed. MEDIA_RECORDER_DATASOURCE_CONFIGURED = 1 << 2, + + // Recorder is ready to start. MEDIA_RECORDER_PREPARED = 1 << 3, + + // Recording is in progress. MEDIA_RECORDER_RECORDING = 1 << 4, }; // The "msg" code passed to the listener in notify. enum media_recorder_event_type { + MEDIA_RECORDER_EVENT_LIST_START = 1, MEDIA_RECORDER_EVENT_ERROR = 1, - MEDIA_RECORDER_EVENT_INFO = 2 + MEDIA_RECORDER_EVENT_INFO = 2, + MEDIA_RECORDER_EVENT_LIST_END = 99, + + // Track related event types + MEDIA_RECORDER_TRACK_EVENT_LIST_START = 100, + MEDIA_RECORDER_TRACK_EVENT_ERROR = 100, + MEDIA_RECORDER_TRACK_EVENT_INFO = 101, + MEDIA_RECORDER_TRACK_EVENT_LIST_END = 1000, }; +/* + * The (part of) "what" code passed to the listener in notify. + * When the error or info type is track specific, the what has + * the following layout: + * the left-most 16-bit is meant for error or info type. + * the right-most 4-bit is meant for track id. + * the rest is reserved. + * + * | track id | reserved | error or info type | + * 31 28 16 0 + * + */ enum media_recorder_error_type { - MEDIA_RECORDER_ERROR_UNKNOWN = 1 + MEDIA_RECORDER_ERROR_UNKNOWN = 1, + + // Track related error type + MEDIA_RECORDER_TRACK_ERROR_LIST_START = 100, + MEDIA_RECORDER_TRACK_ERROR_GENERAL = 100, + MEDIA_RECORDER_ERROR_VIDEO_NO_SYNC_FRAME = 200, + MEDIA_RECORDER_TRACK_ERROR_LIST_END = 1000, }; // The codes are distributed as follow: @@ -141,11 +168,15 @@ enum media_recorder_error_type { // enum media_recorder_info_type { MEDIA_RECORDER_INFO_UNKNOWN = 1, + MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801, - MEDIA_RECORDER_INFO_COMPLETION_STATUS = 802, - MEDIA_RECORDER_INFO_PROGRESS_FRAME_STATUS = 803, - MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS = 804, + + // All track related informtional events start here + MEDIA_RECORDER_TRACK_INFO_LIST_START = 1000, + MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS = 1000, + MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME = 1001, + MEDIA_RECORDER_TRACK_INFO_LIST_END = 2000, }; // ---------------------------------------------------------------------------- diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index d12ee9c..0b79324 100644 --- a/include/media/stagefright/AudioPlayer.h +++ b/include/media/stagefright/AudioPlayer.h @@ -108,6 +108,8 @@ private: void reset(); + uint32_t getNumFramesPendingPlayout() const; + AudioPlayer(const AudioPlayer &); AudioPlayer &operator=(const AudioPlayer &); }; diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h index f95e56a..d30e908 100644 --- a/include/media/stagefright/DataSource.h +++ b/include/media/stagefright/DataSource.h @@ -75,10 +75,10 @@ public: static void RegisterDefaultSniffers(); // for DRM - virtual DecryptHandle* DrmInitialization() { + virtual sp<DecryptHandle> DrmInitialization() { return NULL; } - virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {}; + virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {}; virtual String8 getUri() { return String8(); diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h index 51a4343..6cf86dc 100644 --- a/include/media/stagefright/FileSource.h +++ b/include/media/stagefright/FileSource.h @@ -38,9 +38,9 @@ public: virtual status_t getSize(off64_t *size); - virtual DecryptHandle* DrmInitialization(); + virtual sp<DecryptHandle> DrmInitialization(); - virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client); + virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); protected: virtual ~FileSource(); @@ -52,7 +52,7 @@ private: Mutex mLock; /*for DRM*/ - DecryptHandle *mDecryptHandle; + sp<DecryptHandle> mDecryptHandle; DrmManagerClient *mDrmManagerClient; int64_t mDrmBufOffset; int64_t mDrmBufSize; diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 5c5229d..15f86ea 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -157,7 +157,7 @@ private: bool use32BitFileOffset() const; bool exceedsFileDurationLimit(); bool isFileStreamable() const; - void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK); + void trackProgressStatus(size_t trackId, int64_t timeUs, status_t err = OK); void writeCompositionMatrix(int32_t degrees); MPEG4Writer(const MPEG4Writer &); diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 9e0b5bb..a59d9e5 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -226,7 +226,8 @@ private: int dispatch_set_buffer_count(va_list args); int dispatch_set_buffers_geometry(va_list args); int dispatch_set_buffers_transform(va_list args); - + int dispatch_set_buffers_timestamp(va_list args); + void setUsage(uint32_t reqUsage); int connect(int api); int disconnect(int api); @@ -234,6 +235,7 @@ private: int setBufferCount(int bufferCount); int setBuffersGeometry(int w, int h, int format); int setBuffersTransform(int transform); + int setBuffersTimestamp(int64_t timestamp); /* * private stuff... diff --git a/include/ui/Input.h b/include/ui/Input.h index d9d77c4..8e8b61b 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -27,6 +27,7 @@ #include <utils/Timers.h> #include <utils/RefBase.h> #include <utils/String8.h> +#include <utils/BitSet.h> #ifdef HAVE_ANDROID_OS class SkMatrix; @@ -208,6 +209,13 @@ struct PointerCoords { status_t writeToParcel(Parcel* parcel) const; #endif + bool operator==(const PointerCoords& other) const; + inline bool operator!=(const PointerCoords& other) const { + return !(*this == other); + } + + void copyFrom(const PointerCoords& other); + private: void tooManyAxes(int axis); }; @@ -303,6 +311,13 @@ public: inline int32_t getAction() const { return mAction; } + inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } + + inline int32_t getActionIndex() const { + return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) + >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + } + inline void setAction(int32_t action) { mAction = action; } inline int32_t getFlags() const { return mFlags; } @@ -450,6 +465,8 @@ public: AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex); } + ssize_t findPointerIndex(int32_t pointerId) const; + void initialize( int32_t deviceId, int32_t source, @@ -543,6 +560,67 @@ private: }; /* + * Calculates the velocity of pointer movements over time. + */ +class VelocityTracker { +public: + struct Position { + float x, y; + }; + + VelocityTracker(); + + // Resets the velocity tracker state. + void clear(); + + // Resets the velocity tracker state for specific pointers. + // Call this method when some pointers have changed and may be reusing + // an id that was assigned to a different pointer earlier. + void clearPointers(BitSet32 idBits); + + // Adds movement information for a set of pointers. + // The idBits bitfield specifies the pointer ids of the pointers whose positions + // are included in the movement. + // The positions array contains position information for each pointer in order by + // increasing id. Its size should be equal to the number of one bits in idBits. + void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions); + + // Adds movement information for all pointers in a MotionEvent, including historical samples. + void addMovement(const MotionEvent* event); + + // Gets the velocity of the specified pointer id in position units per second. + // Returns false and sets the velocity components to zero if there is no movement + // information for the pointer. + bool getVelocity(uint32_t id, float* outVx, float* outVy) const; + + // Gets the active pointer id, or -1 if none. + inline int32_t getActivePointerId() const { return mActivePointerId; } + + // Gets a bitset containing all pointer ids from the most recent movement. + inline BitSet32 getCurrentPointerIdBits() const { return mMovements[mIndex].idBits; } + +private: + // Number of samples to keep. + static const uint32_t HISTORY_SIZE = 10; + + // Oldest sample to consider when calculating the velocity. + static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms + + // The minimum duration between samples when estimating velocity. + static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms + + struct Movement { + nsecs_t eventTime; + BitSet32 idBits; + Position positions[MAX_POINTERS]; + }; + + uint32_t mIndex; + Movement mMovements[HISTORY_SIZE]; + int32_t mActivePointerId; +}; + +/* * Describes the characteristics and capabilities of an input device. */ class InputDeviceInfo { diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index b912e9b..8383957 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -228,6 +228,9 @@ static const KeycodeLabel KEYCODES[] = { { "BUTTON_14", 201 }, { "BUTTON_15", 202 }, { "BUTTON_16", 203 }, + { "LANGUAGE_SWITCH", 204 }, + { "MANNER_MODE", 205 }, + { "3D_MODE", 206 }, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h index 0fc1ddf..972e799 100644 --- a/include/ui/egl/android_natives.h +++ b/include/ui/egl/android_natives.h @@ -57,7 +57,7 @@ typedef struct android_native_base_t { /* a magic value defined by the actual EGL native type */ int magic; - + /* the sizeof() of the actual EGL native type */ int version; @@ -129,6 +129,7 @@ enum { NATIVE_WINDOW_SET_BUFFER_COUNT, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, + NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP, }; /* parameter for NATIVE_WINDOW_[DIS]CONNECT */ @@ -157,7 +158,15 @@ enum { NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, // SurfaceTextureClient }; -struct ANativeWindow +/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP + * + * Special timestamp value to indicate that timestamps should be auto-generated + * by the native window when queueBuffer is called. This is equal to INT64_MIN, + * defined directly to avoid problems with C99/C++ inclusion of stdint.h. + */ +const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1); + +struct ANativeWindow { #ifdef __cplusplus ANativeWindow() @@ -262,7 +271,8 @@ struct ANativeWindow * NATIVE_WINDOW_SET_BUFFER_COUNT * NATIVE_WINDOW_SET_BUFFERS_GEOMETRY * NATIVE_WINDOW_SET_BUFFERS_TRANSFORM - * + * NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP + * */ int (*perform)(struct ANativeWindow* window, @@ -281,9 +291,6 @@ struct ANativeWindow void* reserved_proc[2]; }; -// Backwards compatibility... please switch to ANativeWindow. -typedef struct ANativeWindow android_native_window_t; - /* * native_window_set_usage(..., usage) * Sets the intended usage flags for the next buffers @@ -389,6 +396,22 @@ static inline int native_window_set_buffers_transform( transform); } +/* + * native_window_set_buffers_timestamp(..., int64_t timestamp) + * All buffers queued after this call will be associated with the timestamp + * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO + * (the default), timestamps will be generated automatically when queueBuffer is + * called. The timestamp is measured in nanoseconds, and must be monotonically + * increasing. + */ +static inline int native_window_set_buffers_timestamp( + ANativeWindow* window, + int64_t timestamp) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP, + timestamp); +} + // --------------------------------------------------------------------------- /* FIXME: this is legacy for pixmaps */ diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h index f5dbcd9..de748b5 100644 --- a/include/utils/BitSet.h +++ b/include/utils/BitSet.h @@ -61,6 +61,16 @@ struct BitSet32 { // Result is undefined if all bits are marked. inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); } + // Finds the last marked bit in the set. + // Result is undefined if all bits are unmarked. + inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); } + + // Gets the index of the specified bit in the set, which is the number of + // marked bits that appear before the specified bit. + inline uint32_t getIndexOfBit(uint32_t n) const { + return __builtin_popcount(value & ~(0xffffffffUL >> n)); + } + inline bool operator== (const BitSet32& other) const { return value == other.value; } inline bool operator!= (const BitSet32& other) const { return value != other.value; } }; diff --git a/include/utils/GenerationCache.h b/include/utils/GenerationCache.h new file mode 100644 index 0000000..bb9ddd6 --- /dev/null +++ b/include/utils/GenerationCache.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2010 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_UTILS_GENERATION_CACHE_H +#define ANDROID_UTILS_GENERATION_CACHE_H + +#include <utils/KeyedVector.h> +#include <utils/RefBase.h> + +namespace android { + +/** + * GenerationCache callback used when an item is removed + */ +template<typename EntryKey, typename EntryValue> +class OnEntryRemoved { +public: + virtual ~OnEntryRemoved() { }; + virtual void operator()(EntryKey& key, EntryValue& value) = 0; +}; // class OnEntryRemoved + +template<typename EntryKey, typename EntryValue> +struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > { + Entry() { } + Entry(const Entry<EntryKey, EntryValue>& e): + key(e.key), value(e.value), parent(e.parent), child(e.child) { } + Entry(sp<Entry<EntryKey, EntryValue> > e): + key(e->key), value(e->value), parent(e->parent), child(e->child) { } + + EntryKey key; + EntryValue value; + + sp<Entry<EntryKey, EntryValue> > parent; + sp<Entry<EntryKey, EntryValue> > child; +}; // struct Entry + +/** + * A LRU type cache + */ +template<typename K, typename V> +class GenerationCache { +public: + GenerationCache(uint32_t maxCapacity); + virtual ~GenerationCache(); + + enum Capacity { + kUnlimitedCapacity, + }; + + void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener); + + void clear(); + + bool contains(K key) const; + V get(K key); + K getKeyAt(uint32_t index) const; + bool put(K key, V value); + V remove(K key); + V removeOldest(); + V getValueAt(uint32_t index) const; + + uint32_t size() const; + + void addToCache(sp<Entry<K, V> > entry, K key, V value); + void attachToCache(sp<Entry<K, V> > entry); + void detachFromCache(sp<Entry<K, V> > entry); + + V removeAt(ssize_t index); + +private: + KeyedVector<K, sp<Entry<K, V> > > mCache; + uint32_t mMaxCapacity; + + OnEntryRemoved<K, V>* mListener; + + sp<Entry<K, V> > mOldest; + sp<Entry<K, V> > mYoungest; +}; // class GenerationCache + +template<typename K, typename V> +GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), + mListener(NULL) { +}; + +template<typename K, typename V> +GenerationCache<K, V>::~GenerationCache() { + clear(); +}; + +template<typename K, typename V> +uint32_t GenerationCache<K, V>::size() const { + return mCache.size(); +} + +/** + * Should be set by the user of the Cache so that the callback is called whenever an item is + * removed from the cache + */ +template<typename K, typename V> +void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) { + mListener = listener; +} + +template<typename K, typename V> +void GenerationCache<K, V>::clear() { + if (mListener) { + for (uint32_t i = 0; i < mCache.size(); i++) { + sp<Entry<K, V> > entry = mCache.valueAt(i); + if (mListener) { + (*mListener)(entry->key, entry->value); + } + } + } + mCache.clear(); + mYoungest.clear(); + mOldest.clear(); +} + +template<typename K, typename V> +bool GenerationCache<K, V>::contains(K key) const { + return mCache.indexOfKey(key) >= 0; +} + +template<typename K, typename V> +K GenerationCache<K, V>::getKeyAt(uint32_t index) const { + return mCache.keyAt(index); +} + +template<typename K, typename V> +V GenerationCache<K, V>::getValueAt(uint32_t index) const { + return mCache.valueAt(index)->value; +} + +template<typename K, typename V> +V GenerationCache<K, V>::get(K key) { + ssize_t index = mCache.indexOfKey(key); + if (index >= 0) { + sp<Entry<K, V> > entry = mCache.valueAt(index); + if (entry.get()) { + detachFromCache(entry); + attachToCache(entry); + return entry->value; + } + } + + return NULL; +} + +template<typename K, typename V> +bool GenerationCache<K, V>::put(K key, V value) { + if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) { + removeOldest(); + } + + ssize_t index = mCache.indexOfKey(key); + if (index < 0) { + sp<Entry<K, V> > entry = new Entry<K, V>; + addToCache(entry, key, value); + return true; + } + + return false; +} + +template<typename K, typename V> +void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) { + entry->key = key; + entry->value = value; + mCache.add(key, entry); + attachToCache(entry); +} + +template<typename K, typename V> +V GenerationCache<K, V>::remove(K key) { + ssize_t index = mCache.indexOfKey(key); + if (index >= 0) { + return removeAt(index); + } + + return NULL; +} + +template<typename K, typename V> +V GenerationCache<K, V>::removeAt(ssize_t index) { + sp<Entry<K, V> > entry = mCache.valueAt(index); + if (mListener) { + (*mListener)(entry->key, entry->value); + } + mCache.removeItemsAt(index, 1); + detachFromCache(entry); + + return entry->value; +} + +template<typename K, typename V> +V GenerationCache<K, V>::removeOldest() { + if (mOldest.get()) { + ssize_t index = mCache.indexOfKey(mOldest->key); + if (index >= 0) { + return removeAt(index); + } + } + + return NULL; +} + +template<typename K, typename V> +void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) { + if (!mYoungest.get()) { + mYoungest = mOldest = entry; + } else { + entry->parent = mYoungest; + mYoungest->child = entry; + mYoungest = entry; + } +} + +template<typename K, typename V> +void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) { + if (entry->parent.get()) { + entry->parent->child = entry->child; + } + + if (entry->child.get()) { + entry->child->parent = entry->parent; + } + + if (mOldest == entry) { + mOldest = entry->child; + } + + if (mYoungest == entry) { + mYoungest = entry->parent; + } + + entry->parent.clear(); + entry->child.clear(); +} + +}; // namespace android + +#endif // ANDROID_UTILS_GENERATION_CACHE_H diff --git a/include/utils/Timers.h b/include/utils/Timers.h index 9a9e07c..8b4d322 100644 --- a/include/utils/Timers.h +++ b/include/utils/Timers.h @@ -88,6 +88,16 @@ nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC); nsecs_t systemTime(int clock); #endif // def __cplusplus +/** + * Returns the number of milliseconds to wait between the reference time and the timeout time. + * If the timeout is in the past relative to the reference time, returns 0. + * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time, + * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay. + * Otherwise, returns the difference between the reference time and timeout time + * rounded up to the next millisecond. + */ +int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime); + #ifdef __cplusplus } // extern "C" #endif diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk index 2f16923..b17b3d2 100644 --- a/libs/camera/Android.mk +++ b/libs/camera/Android.mk @@ -13,7 +13,6 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libbinder \ libhardware \ - libsurfaceflinger_client \ libui \ libgui diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index d1a6af1..58bb0d3 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -10,7 +10,15 @@ LOCAL_SRC_FILES:= \ SensorEventQueue.cpp \ SensorManager.cpp \ SurfaceTexture.cpp \ - SurfaceTextureClient.cpp + SurfaceTextureClient.cpp \ + ISurfaceComposer.cpp \ + ISurface.cpp \ + ISurfaceComposerClient.cpp \ + IGraphicBufferAlloc.cpp \ + LayerState.cpp \ + SharedBufferStack.cpp \ + Surface.cpp \ + SurfaceComposerClient.cpp \ LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -21,7 +29,6 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libEGL \ libGLESv2 \ - libsurfaceflinger_client LOCAL_MODULE:= libgui diff --git a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index e05da72..e05da72 100644 --- a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/gui/ISurface.cpp index 23b90af..23b90af 100644 --- a/libs/surfaceflinger_client/ISurface.cpp +++ b/libs/gui/ISurface.cpp diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8951c3f..8951c3f 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp diff --git a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 7730eb1..7730eb1 100644 --- a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp index d661fd5..bc14ad5 100644 --- a/libs/gui/ISurfaceTexture.cpp +++ b/libs/gui/ISurfaceTexture.cpp @@ -88,10 +88,11 @@ public: return result; } - virtual status_t queueBuffer(int buf) { + virtual status_t queueBuffer(int buf, int64_t timestamp) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(buf); + data.writeInt64(timestamp); remote()->transact(QUEUE_BUFFER, data, &reply); status_t result = reply.readInt32(); return result; @@ -174,7 +175,8 @@ status_t BnSurfaceTexture::onTransact( case QUEUE_BUFFER: { CHECK_INTERFACE(ISurfaceTexture, data, reply); int buf = data.readInt32(); - status_t result = queueBuffer(buf); + int64_t timestamp = data.readInt64(); + status_t result = queueBuffer(buf, timestamp); reply->writeInt32(result); return NO_ERROR; } break; @@ -196,7 +198,6 @@ status_t BnSurfaceTexture::onTransact( return NO_ERROR; } break; case SET_TRANSFORM: { - Rect reg; CHECK_INTERFACE(ISurfaceTexture, data, reply); uint32_t transform = data.readInt32(); status_t result = setTransform(transform); diff --git a/libs/surfaceflinger_client/LayerState.cpp b/libs/gui/LayerState.cpp index 01c4c7e..01c4c7e 100644 --- a/libs/surfaceflinger_client/LayerState.cpp +++ b/libs/gui/LayerState.cpp diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp index 7505d53..7505d53 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/gui/SharedBufferStack.cpp diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/gui/Surface.cpp index 21d509a..0dfbf01 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -753,6 +753,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: res = dispatch_set_buffers_transform( args ); break; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + res = dispatch_set_buffers_timestamp( args ); + break; default: res = NAME_NOT_FOUND; break; @@ -792,6 +795,11 @@ int Surface::dispatch_set_buffers_transform(va_list args) { return setBuffersTransform(transform); } +int Surface::dispatch_set_buffers_timestamp(va_list args) { + int64_t timestamp = va_arg(args, int64_t); + return setBuffersTimestamp(timestamp); +} + void Surface::setUsage(uint32_t reqUsage) { Mutex::Autolock _l(mSurfaceLock); @@ -910,6 +918,13 @@ int Surface::setBuffersTransform(int transform) return NO_ERROR; } +int Surface::setBuffersTimestamp(int64_t timestamp) +{ + // Surface doesn't really have anything meaningful to do with timestamps + // so they'll just be dropped here. + return NO_ERROR; +} + // ---------------------------------------------------------------------------- int Surface::getConnectedApi() const diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d336724..d336724 100644 --- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 5c6d71b..cdaca47 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -76,9 +76,15 @@ static float mtxRot270[16] = { static void mtxMul(float out[16], const float a[16], const float b[16]); SurfaceTexture::SurfaceTexture(GLuint tex) : - mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), - mCurrentTransform(0), mLastQueued(INVALID_BUFFER_SLOT), - mLastQueuedTransform(0), mNextTransform(0), mTexName(tex) { + mBufferCount(MIN_BUFFER_SLOTS), + mCurrentTexture(INVALID_BUFFER_SLOT), + mCurrentTransform(0), + mCurrentTimestamp(0), + mLastQueued(INVALID_BUFFER_SLOT), + mLastQueuedTransform(0), + mLastQueuedTimestamp(0), + mNextTransform(0), + mTexName(tex) { LOGV("SurfaceTexture::SurfaceTexture"); for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; @@ -153,7 +159,7 @@ status_t SurfaceTexture::dequeueBuffer(int *buf) { return OK; } -status_t SurfaceTexture::queueBuffer(int buf) { +status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { LOGV("SurfaceTexture::queueBuffer"); Mutex::Autolock lock(mMutex); if (buf < 0 || mBufferCount <= buf) { @@ -172,6 +178,7 @@ status_t SurfaceTexture::queueBuffer(int buf) { mLastQueued = buf; mLastQueuedCrop = mNextCrop; mLastQueuedTransform = mNextTransform; + mLastQueuedTimestamp = timestamp; if (mFrameAvailableListener != 0) { mFrameAvailableListener->onFrameAvailable(); } @@ -246,12 +253,13 @@ status_t SurfaceTexture::updateTexImage() { mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer; mCurrentCrop = mLastQueuedCrop; mCurrentTransform = mLastQueuedTransform; + mCurrentTimestamp = mLastQueuedTimestamp; } return OK; } void SurfaceTexture::getTransformMatrix(float mtx[16]) { - LOGV("SurfaceTexture::updateTexImage"); + LOGV("SurfaceTexture::getTransformMatrix"); Mutex::Autolock lock(mMutex); float xform[16]; @@ -342,6 +350,12 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { mtxMul(mtx, mtxFlipV, mtxBeforeFlipV); } +nsecs_t SurfaceTexture::getTimestamp() { + LOGV("SurfaceTexture::getTimestamp"); + Mutex::Autolock lock(mMutex); + return mCurrentTimestamp; +} + void SurfaceTexture::setFrameAvailableListener( const sp<FrameAvailableListener>& l) { LOGV("SurfaceTexture::setFrameAvailableListener"); diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 7f1d9cb..a4812d0 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -26,7 +26,8 @@ namespace android { SurfaceTextureClient::SurfaceTextureClient( const sp<ISurfaceTexture>& surfaceTexture): mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(1), - mReqHeight(1), mReqFormat(DEFAULT_FORMAT), mReqUsage(0), mMutex() { + mReqHeight(1), mReqFormat(DEFAULT_FORMAT), mReqUsage(0), + mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = setSwapInterval; ANativeWindow::dequeueBuffer = dequeueBuffer; @@ -135,9 +136,17 @@ int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) { int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { LOGV("SurfaceTextureClient::queueBuffer"); Mutex::Autolock lock(mMutex); + int64_t timestamp; + if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { + timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + LOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms", + timestamp / 1000000.f); + } else { + timestamp = mTimestamp; + } for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i]->handle == buffer->handle) { - return mSurfaceTexture->queueBuffer(i); + return mSurfaceTexture->queueBuffer(i, timestamp); } } LOGE("queueBuffer: unknown buffer queued"); @@ -196,6 +205,9 @@ int SurfaceTextureClient::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: res = dispatchSetBuffersTransform(args); break; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + res = dispatchSetBuffersTimestamp(args); + break; default: res = NAME_NOT_FOUND; break; @@ -240,6 +252,11 @@ int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) { return setBuffersTransform(transform); } +int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) { + int64_t timestamp = va_arg(args, int64_t); + return setBuffersTimestamp(timestamp); +} + int SurfaceTextureClient::connect(int api) { LOGV("SurfaceTextureClient::connect"); // XXX: Implement this! @@ -323,6 +340,14 @@ int SurfaceTextureClient::setBuffersTransform(int transform) return err; } +int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp) +{ + LOGV("SurfaceTextureClient::setBuffersTimestamp"); + Mutex::Autolock lock(mMutex); + mTimestamp = timestamp; + return NO_ERROR; +} + void SurfaceTextureClient::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i] = 0; diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk index 7516299..ecd0995 100644 --- a/libs/gui/tests/Android.mk +++ b/libs/gui/tests/Android.mk @@ -9,6 +9,7 @@ LOCAL_MODULE := SurfaceTexture_test LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ + Surface_test.cpp \ SurfaceTextureClient_test.cpp \ SurfaceTexture_test.cpp \ @@ -20,7 +21,6 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libgui \ libstlport \ - libsurfaceflinger_client \ libui \ libutils \ diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index fd07479..fd07479 100644 --- a/libs/surfaceflinger_client/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index f4a0161..b465fee 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -42,7 +42,6 @@ ifeq ($(USE_OPENGL_RENDERER),true) LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui LOCAL_MODULE := libhwui LOCAL_MODULE_TAGS := optional - LOCAL_PRELINK_MODULE := false include $(BUILD_SHARED_LIBRARY) diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h index 14471bc..f74238e 100644 --- a/libs/hwui/Debug.h +++ b/libs/hwui/Debug.h @@ -26,7 +26,7 @@ // Turn on to enable memory usage summary on each frame #define DEBUG_MEMORY_USAGE 0 -// Turn on to enable layers debugging when renderered as regions +// Turn on to enable layers debugging when rendered as regions #define DEBUG_LAYERS_AS_REGIONS 0 // Turn on to display debug info about vertex/fragment shaders @@ -35,7 +35,7 @@ // Turn on to display info about layers #define DEBUG_LAYERS 0 -// Turn on to display debug infor about 9patch objects +// Turn on to display debug info about 9patch objects #define DEBUG_PATCHES 0 // Turn on to display vertex and tex coords data about 9patch objects // This flag requires DEBUG_PATCHES to be turned on diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 868290b..c7459d1 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -53,6 +53,7 @@ const char* DisplayList::OP_NAMES[] = { "DrawArc", "DrawPath", "DrawLines", + "DrawPoints", "DrawText", "ResetShader", "SetupShader", @@ -92,13 +93,11 @@ void DisplayList::clearResources() { mPaints.clear(); for (size_t i = 0; i < mPaths.size(); i++) { - delete mPaths.itemAt(i); + SkPath* path = mPaths.itemAt(i); + caches.pathCache.remove(path); + delete path; } mPaths.clear(); - for (size_t i = 0; i < mOriginalPaths.size(); i++) { - caches.resourceCache.decrementRefcount(mOriginalPaths.itemAt(i)); - } - mOriginalPaths.clear(); for (size_t i = 0; i < mMatrices.size(); i++) { delete mMatrices.itemAt(i); @@ -150,13 +149,6 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde mPaths.add(paths.itemAt(i)); } - const Vector<SkPath*> &originalPaths = recorder.getOriginalPaths(); - for (size_t i = 0; i < originalPaths.size(); i++) { - SkPath* path = originalPaths.itemAt(i); - mOriginalPaths.add(path); - caches.resourceCache.incrementRefcount(path); - } - const Vector<SkMatrix*> &matrices = recorder.getMatrices(); for (size_t i = 0; i < matrices.size(); i++) { mMatrices.add(matrices.itemAt(i)); @@ -452,6 +444,13 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) renderer.drawLines(points, count, getPaint()); } break; + case DrawPoints: { + int count = 0; + float* points = getFloats(count); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); + renderer.drawPoints(points, count, getPaint()); + } + break; case DrawText: { getText(&text); int count = getInt(); @@ -533,12 +532,6 @@ void DisplayListRenderer::reset() { } mBitmapResources.clear(); - for (size_t i = 0; i < mOriginalPaths.size(); i++) { - SkPath* resource = mOriginalPaths.itemAt(i); - caches.resourceCache.decrementRefcount(resource); - } - mOriginalPaths.clear(); - for (size_t i = 0; i < mShaders.size(); i++) { caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); } @@ -804,6 +797,12 @@ void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) { addPaint(paint); } +void DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) { + addOp(DisplayList::DrawPoints); + addFloats(points, count); + addPaint(paint); +} + void DisplayListRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint) { addOp(DisplayList::DrawText); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 6fc315c..da57e4a 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -89,6 +89,7 @@ public: DrawArc, DrawPath, DrawLines, + DrawPoints, DrawText, ResetShader, SetupShader, @@ -193,7 +194,6 @@ private: Vector<SkPaint*> mPaints; Vector<SkPath*> mPaths; - Vector<SkPath*> mOriginalPaths; Vector<SkMatrix*> mMatrices; Vector<SkiaShader*> mShaders; @@ -265,6 +265,7 @@ public: float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); void drawPath(SkPath* path, SkPaint* paint); void drawLines(float* points, int count, SkPaint* paint); + void drawPoints(float* points, int count, SkPaint* paint); void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint); void resetShader(); @@ -298,10 +299,6 @@ public: return mPaths; } - const Vector<SkPath*>& getOriginalPaths() const { - return mOriginalPaths; - } - const Vector<SkMatrix*>& getMatrices() const { return mMatrices; } @@ -383,16 +380,9 @@ private: SkPath* pathCopy = mPathMap.valueFor(path); if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) { - if (pathCopy == NULL) { - pathCopy = path; - mOriginalPaths.add(path); - Caches& caches = Caches::getInstance(); - caches.resourceCache.incrementRefcount(path); - } else { - pathCopy = new SkPath(*path); - mPaths.add(pathCopy); - } + pathCopy = new SkPath(*path); mPathMap.add(path, pathCopy); + mPaths.add(pathCopy); } addInt((int) pathCopy); @@ -469,7 +459,6 @@ private: Vector<SkPaint*> mPaints; DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap; - Vector<SkPath*> mOriginalPaths; Vector<SkPath*> mPaths; DefaultKeyedVector<SkPath*, SkPath*> mPathMap; diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index bb28437..26e240f 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -103,6 +103,11 @@ struct Layer { * have been drawn. */ Region region; + /** + * If the region is a rectangle, coordinates of the + * region are stored here. + */ + Rect regionRect; /** * Color filter used to draw this layer. Optional. diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index f92e20b..ba110ec 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -92,11 +92,7 @@ Region* LayerRenderer::getRegion() { void LayerRenderer::generateMesh() { #if RENDER_LAYERS_AS_REGIONS -#if RENDER_LAYERS_RECT_AS_RECT if (mLayer->region.isRect() || mLayer->region.isEmpty()) { -#else - if (mLayer->region.isEmpty()) { -#endif if (mLayer->mesh) { delete mLayer->mesh; delete mLayer->meshIndices; @@ -105,6 +101,20 @@ void LayerRenderer::generateMesh() { mLayer->meshIndices = NULL; mLayer->meshElementCount = 0; } + + const android::Rect& bounds = mLayer->region.getBounds(); + mLayer->regionRect.set(bounds.leftTop().x, bounds.leftTop().y, + bounds.rightBottom().x, bounds.rightBottom().y); + + const float texX = 1.0f / float(mLayer->width); + const float texY = 1.0f / float(mLayer->height); + const float height = mLayer->layer.getHeight(); + mLayer->texCoords.set( + mLayer->regionRect.left * texX, + (height - mLayer->regionRect.top) * texY, + mLayer->regionRect.right * texX, + (height - mLayer->regionRect.bottom) * texY); + return; } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index d9d7d23..6fabbef 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -646,13 +646,14 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { #if RENDER_LAYERS_AS_REGIONS -#if RENDER_LAYERS_RECT_AS_RECT if (layer->region.isRect()) { - composeLayerRect(layer, rect); + const android::Rect& bounds = layer->region.getBounds(); + layer->regionRect.set(bounds.leftTop().x, bounds.leftTop().y, + bounds.rightBottom().x, bounds.rightBottom().y); + composeLayerRect(layer, layer->regionRect); layer->region.clear(); return; } -#endif if (!layer->region.isEmpty()) { size_t count; @@ -881,6 +882,11 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { mDescription.hasAlpha8Texture = isAlpha8; } +void OpenGLRenderer::setupDrawPoint(float pointSize) { + mDescription.isPoint = true; + mDescription.pointSize = pointSize; +} + void OpenGLRenderer::setupDrawColor(int color) { setupDrawColor(color, (color >> 24) & 0xFF); } @@ -989,6 +995,11 @@ void OpenGLRenderer::setupDrawModelView(float left, float top, float right, floa } } +void OpenGLRenderer::setupDrawPointUniforms() { + int slot = mCaches.currentProgram->getUniform("pointSize"); + glUniform1f(slot, mDescription.pointSize); +} + void OpenGLRenderer::setupDrawColorUniforms() { if (mColorSet || (mShader && mSetShaderColor)) { mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); @@ -1072,6 +1083,44 @@ bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, u return false; } +void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) { + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); + + float x = left; + float y = top; + + bool ignoreTransform = false; + if (mSnapshot->transform->isPureTranslate()) { + x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); + y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); + ignoreTransform = true; + } + + setupDraw(); + setupDrawWithTexture(true); + if (paint) { + setupDrawAlpha8Color(paint->getColor(), alpha); + } + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform); + setupDrawTexture(texture->id); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(); + setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + + finishDrawTexture(); +} + void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { const float right = left + bitmap->width(); const float bottom = top + bitmap->height(); @@ -1085,7 +1134,11 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint if (!texture) return; const AutoTexture autoCleanup(texture); - drawTextureRect(left, top, right, bottom, texture, paint); + if (bitmap->getConfig() == SkBitmap::kA8_Config) { + drawAlphaBitmap(texture, left, top, paint); + } else { + drawTextureRect(left, top, right, bottom, texture, paint); + } } void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) { @@ -1388,26 +1441,66 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } else { // TODO: Handle the AA case for (int i = 0; i < count; i += 4) { - const float left = fmin(points[i], points[i + 1]); - const float right = fmax(points[i], points[i + 1]); - const float top = fmin(points[i + 2], points[i + 3]); - const float bottom = fmax(points[i + 2], points[i + 3]); + TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); + TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); - if (!quickReject(left, top, right, bottom)) { - TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); - TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); + generatedVerticesCount += 2; - generatedVerticesCount += 2; + const float left = fmin(points[i], points[i + 2]); + const float right = fmax(points[i], points[i + 2]); + const float top = fmin(points[i + 1], points[i + 3]); + const float bottom = fmax(points[i + 1], points[i + 3]); - dirtyLayer(left, top, right, bottom, *mSnapshot->transform); - } + dirtyLayer(left, top, + right == left ? left + 1 : right, bottom == top ? top + 1 : bottom, + *mSnapshot->transform); } - if (generatedVerticesCount > 0) { - glLineWidth(1.0f); - glDrawArrays(GL_LINES, 0, generatedVerticesCount); - } + glLineWidth(1.0f); + glDrawArrays(GL_LINES, 0, generatedVerticesCount); + } +} + +void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { + if (mSnapshot->isIgnored()) return; + + // TODO: The paint's cap style defines whether the points are square or circular + // TODO: Handle AA for round points + + // A stroke width of 0 has a special meaningin Skia: + // it draws an unscaled 1px point + const bool isHairLine = paint->getStrokeWidth() == 0.0f; + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + int verticesCount = count >> 1; + int generatedVerticesCount = 0; + + TextureVertex pointsData[verticesCount]; + TextureVertex* vertex = &pointsData[0]; + + setupDraw(); + setupDrawPoint(isHairLine ? 1.0f : paint->getStrokeWidth()); + setupDrawColor(paint->getColor(), alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(mode); + setupDrawProgram(); + setupDrawModelViewIdentity(); + setupDrawColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawPointUniforms(); + setupDrawShaderIdentityUniforms(); + setupDrawMesh(vertex); + + for (int i = 0; i < count; i += 2) { + TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); + generatedVerticesCount++; } + + glDrawArrays(GL_POINTS, 0, generatedVerticesCount); } void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { @@ -1658,14 +1751,9 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { #if RENDER_LAYERS_AS_REGIONS if (!layer->region.isEmpty()) { -#if RENDER_LAYERS_RECT_AS_RECT if (layer->region.isRect()) { - const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); - composeLayerRect(layer, r); + composeLayerRect(layer, layer->regionRect); } else if (layer->mesh) { -#else - if (layer->mesh) { -#endif const float a = alpha / 255.0f; const Rect& rect = layer->layer; @@ -1675,13 +1763,11 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { setupDrawColorFilter(); setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); setupDrawProgram(); + setupDrawModelViewTranslate(x, y, + x + layer->layer.getWidth(), y + layer->layer.getHeight()); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); setupDrawTexture(layer->texture); - // TODO: The current layer, if any, will be dirtied with the bounding box - // of the layer we are drawing. Since the layer we are drawing has - // a mesh, we know the dirty region, we should use it instead - setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); glDrawElements(GL_TRIANGLES, layer->meshElementCount, diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 7362473..4b93b80 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -119,6 +119,7 @@ public: float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); virtual void drawPath(SkPath* path, SkPaint* paint); virtual void drawLines(float* points, int count, SkPaint* paint); + virtual void drawPoints(float* points, int count, SkPaint* paint); virtual void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint); @@ -279,6 +280,8 @@ private: void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint); void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p); + void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint); + /** * Draws a textured rectangle with the specified texture. The specified coordinates * are transformed by the current snapshot's transform matrix. @@ -422,6 +425,7 @@ private: * Various methods to setup OpenGL rendering. */ void setupDrawWithTexture(bool isAlpha8 = false); + void setupDrawPoint(float pointSize); void setupDrawColor(int color); void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); @@ -440,6 +444,7 @@ private: bool ignoreTransform = false, bool ignoreModelView = false); void setupDrawModelViewTranslate(float left, float top, float right, float bottom, bool ignoreTransform = false); + void setupDrawPointUniforms(); void setupDrawColorUniforms(); void setupDrawPureColorUniforms(); void setupDrawShaderIdentityUniforms(); diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index dc67e16..7ff8b74 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -41,8 +41,7 @@ struct PathCacheEntry: public ShapeCacheEntry { path = NULL; } - PathCacheEntry(const PathCacheEntry& entry): - ShapeCacheEntry(entry) { + PathCacheEntry(const PathCacheEntry& entry): ShapeCacheEntry(entry) { path = entry.path; } @@ -55,6 +54,7 @@ struct PathCacheEntry: public ShapeCacheEntry { } SkPath* path; + }; // PathCacheEntry /** diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 0b6c7b5..f0bc36b 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -41,6 +41,8 @@ const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n"; const char* gVS_Header_Uniforms = "uniform mat4 transform;\n"; +const char* gVS_Header_Uniforms_IsPoint = + "uniform mediump float pointSize;\n"; const char* gVS_Header_Uniforms_HasGradient[3] = { // Linear "uniform mat4 screenSpace;\n", @@ -51,11 +53,13 @@ const char* gVS_Header_Uniforms_HasGradient[3] = { }; const char* gVS_Header_Uniforms_HasBitmap = "uniform mat4 textureTransform;\n" - "uniform vec2 textureDimension;\n"; + "uniform mediump vec2 textureDimension;\n"; const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; const char* gVS_Header_Varyings_HasBitmap = "varying vec2 outBitmapTexCoords;\n"; +const char* gVS_Header_Varyings_PointHasBitmap = + "varying vec2 outPointBitmapTexCoords;\n"; const char* gVS_Header_Varyings_HasGradient[3] = { // Linear "varying vec2 linear;\n", @@ -78,8 +82,12 @@ const char* gVS_Main_OutGradient[3] = { }; const char* gVS_Main_OutBitmapTexCoords = " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; +const char* gVS_Main_OutPointBitmapTexCoords = + " outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; const char* gVS_Main_Position = " gl_Position = transform * position;\n"; +const char* gVS_Main_PointSize = + " gl_PointSize = pointSize;\n"; const char* gVS_Footer = "}\n\n"; @@ -93,6 +101,9 @@ const char* gFS_Header = "precision mediump float;\n\n"; const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; +const char* gFS_Header_Uniforms_PointHasBitmap = + "uniform vec2 textureDimension;\n" + "uniform float pointSize;\n"; const char* gFS_Uniforms_TextureSampler = "uniform sampler2D sampler;\n"; const char* gFS_Uniforms_GradientSampler[3] = { @@ -121,6 +132,10 @@ const char* gFS_Main = "\nvoid main(void) {\n" " lowp vec4 fragColor;\n"; +const char* gFS_Main_PointBitmapTexCoords = + " vec2 outBitmapTexCoords = outPointBitmapTexCoords + " + "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n"; + // Fast cases const char* gFS_Fast_SingleColor = "\nvoid main(void) {\n" @@ -347,6 +362,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasBitmap) { shader.append(gVS_Header_Uniforms_HasBitmap); } + if (description.isPoint) { + shader.append(gVS_Header_Uniforms_IsPoint); + } // Varyings if (description.hasTexture) { shader.append(gVS_Header_Varyings_HasTexture); @@ -355,7 +373,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Header_Varyings_HasBitmap); + shader.append(description.isPoint ? + gVS_Header_Varyings_PointHasBitmap : + gVS_Header_Varyings_HasBitmap); } // Begin the shader @@ -367,7 +387,12 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description shader.append(gVS_Main_OutGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Main_OutBitmapTexCoords); + shader.append(description.isPoint ? + gVS_Main_OutPointBitmapTexCoords : + gVS_Main_OutBitmapTexCoords); + } + if (description.isPoint) { + shader.append(gVS_Main_PointSize); } // Output transformed position shader.append(gVS_Main_Position); @@ -399,7 +424,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Header_Varyings_HasBitmap); + shader.append(description.isPoint ? + gVS_Header_Varyings_PointHasBitmap : + gVS_Header_Varyings_HasBitmap); } // Uniforms @@ -417,9 +444,13 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } + if (description.hasBitmap && description.isPoint) { + shader.append(gFS_Header_Uniforms_PointHasBitmap); + } // Optimization for common cases - if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone) { + if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && + !description.isPoint) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; @@ -507,6 +538,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchGradient[description.gradientType]); } if (description.hasBitmap) { + if (description.isPoint) { + shader.append(gFS_Main_PointBitmapTexCoords); + } if (!description.isBitmapNpot) { shader.append(gFS_Main_FetchBitmap); } else { diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index ead5b92..737d91b 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -71,7 +71,9 @@ namespace uirenderer { #define PROGRAM_BITMAP_WRAPT_SHIFT 11 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 -#define PROGRAM_MODULATE 35 +#define PROGRAM_MODULATE_SHIFT 35 + +#define PROGRAM_IS_POINT_SHIFT 36 /////////////////////////////////////////////////////////////////////////////// // Types @@ -135,6 +137,9 @@ struct ProgramDescription { SkXfermode::Mode framebufferMode; bool swapSrcDst; + bool isPoint; + float pointSize; + /** * Resets this description. All fields are reset back to the default * values they hold after building a new instance. @@ -162,6 +167,9 @@ struct ProgramDescription { framebufferMode = SkXfermode::kClear_Mode; swapSrcDst = false; + + isPoint = false; + pointSize = 0.0f; } /** @@ -223,7 +231,8 @@ struct ProgramDescription { } key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; - if (modulate) key |= programid(0x1) << PROGRAM_MODULATE; + if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT; + if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT; return key; } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 1aef99b..2d8b6f3 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -27,8 +27,6 @@ // If turned on, layers drawn inside FBOs are optimized with regions #define RENDER_LAYERS_AS_REGIONS 1 -// If turned on, layers that map to a single rect are drawn as a rect -#define RENDER_LAYERS_RECT_AS_RECT 0 /** * Debug level for app developers. diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h index 4c626dd..b5cc29c 100644 --- a/libs/hwui/ShapeCache.h +++ b/libs/hwui/ShapeCache.h @@ -89,14 +89,17 @@ struct ShapeCacheEntry { join = SkPaint::kDefault_Join; cap = SkPaint::kDefault_Cap; style = SkPaint::kFill_Style; - miter = 4.0f; - strokeWidth = 1.0f; + float v = 4.0f; + miter = *(uint32_t*) &v; + v = 1.0f; + strokeWidth = *(uint32_t*) &v; + pathEffect = NULL; } ShapeCacheEntry(const ShapeCacheEntry& entry): shapeType(entry.shapeType), join(entry.join), cap(entry.cap), style(entry.style), miter(entry.miter), - strokeWidth(entry.strokeWidth) { + strokeWidth(entry.strokeWidth), pathEffect(entry.pathEffect) { } ShapeCacheEntry(ShapeType type, SkPaint* paint) { @@ -108,18 +111,19 @@ struct ShapeCacheEntry { v = paint->getStrokeWidth(); strokeWidth = *(uint32_t*) &v; style = paint->getStyle(); + pathEffect = paint->getPathEffect(); } virtual ~ShapeCacheEntry() { } - // shapeType must be checked in subclasses operator< ShapeType shapeType; SkPaint::Join join; SkPaint::Cap cap; SkPaint::Style style; uint32_t miter; uint32_t strokeWidth; + SkPathEffect* pathEffect; bool operator<(const ShapeCacheEntry& rhs) const { LTE_INT(shapeType) { @@ -128,7 +132,9 @@ struct ShapeCacheEntry { LTE_INT(style) { LTE_INT(miter) { LTE_INT(strokeWidth) { - return lessThan(rhs); + LTE_INT(pathEffect) { + return lessThan(rhs); + } } } } diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 0836887..14152d8 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -28,7 +28,6 @@ RSG_GENERATOR:=$(LOCAL_BUILT_MODULE) # slangdata_output_var_name := rs_runtime_lib_bc # LOCAL_MODULE := librslib_rt -# LOCAL_PRELINK_MODULE := false # LOCAL_MODULE_CLASS := STATIC_LIBRARIES # LOCAL_MODULE_TAGS := optional @@ -114,7 +113,9 @@ LOCAL_SRC_FILES:= \ rsStream.cpp \ rsThreadIO.cpp \ rsType.cpp \ - rsVertexArray.cpp + rsVertexArray.cpp \ + driver/rsdBcc.cpp \ + driver/rsdCore.cpp LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h index ffa9a8c..cb6d7e0 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -24,52 +24,7 @@ extern "C" { #endif -////////////////////////////////////////////////////// -// - -typedef void * RsAsyncVoidPtr; - -typedef void * RsAdapter1D; -typedef void * RsAdapter2D; -typedef void * RsAllocation; -typedef void * RsAnimation; -typedef void * RsContext; -typedef void * RsDevice; -typedef void * RsElement; -typedef void * RsFile; -typedef void * RsFont; -typedef void * RsSampler; -typedef void * RsScript; -typedef void * RsMesh; -typedef void * RsType; -typedef void * RsObjectBase; - -typedef void * RsProgram; -typedef void * RsProgramVertex; -typedef void * RsProgramFragment; -typedef void * RsProgramStore; -typedef void * RsProgramRaster; - -typedef void (* RsBitmapCallback_t)(void *); - -enum RsDeviceParam { - RS_DEVICE_PARAM_FORCE_SOFTWARE_GL, - RS_DEVICE_PARAM_COUNT -}; - -typedef struct { - uint32_t colorMin; - uint32_t colorPref; - uint32_t alphaMin; - uint32_t alphaPref; - uint32_t depthMin; - uint32_t depthPref; - uint32_t stencilMin; - uint32_t stencilPref; - uint32_t samplesMin; - uint32_t samplesPref; - float samplesQ; -} RsSurfaceConfig; +#include "RenderScriptDefines.h" RsDevice rsDeviceCreate(); void rsDeviceDestroy(RsDevice); @@ -80,258 +35,12 @@ RsContext rsContextCreateGL(RsDevice, uint32_t version, RsSurfaceConfig sc, uint32_t dpi); void rsContextDestroy(RsContext); -enum RsMessageToClientType { - RS_MESSAGE_TO_CLIENT_NONE = 0, - RS_MESSAGE_TO_CLIENT_EXCEPTION = 1, - RS_MESSAGE_TO_CLIENT_RESIZE = 2, - RS_MESSAGE_TO_CLIENT_ERROR = 3, - RS_MESSAGE_TO_CLIENT_USER = 4 -}; - RsMessageToClientType rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait); RsMessageToClientType rsContextPeekMessage(RsContext vrsc, size_t *receiveLen, uint32_t *subID, bool wait); void rsContextInitToClient(RsContext); void rsContextDeinitToClient(RsContext); -#define RS_MAX_TEXTURE 2 -#define RS_MAX_ATTRIBS 16 - - -enum RsAllocationUsageType { - RS_ALLOCATION_USAGE_SCRIPT = 0x0001, - RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE = 0x0002, - RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004, - RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008, - - RS_ALLOCATION_USAGE_ALL = 0x000F -}; - -enum RsAllocationMipmapControl { - RS_ALLOCATION_MIPMAP_NONE = 0, - RS_ALLOCATION_MIPMAP_FULL = 1, - RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE = 2 -}; - -enum RsAllocationCubemapFace { - RS_ALLOCATION_CUBMAP_FACE_POSITVE_X = 0, - RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_X = 1, - RS_ALLOCATION_CUBMAP_FACE_POSITVE_Y = 2, - RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Y = 3, - RS_ALLOCATION_CUBMAP_FACE_POSITVE_Z = 4, - RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Z = 5 -}; - -enum RsDataType { - RS_TYPE_NONE, - RS_TYPE_FLOAT_16, - RS_TYPE_FLOAT_32, - 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, -}; - -enum RsDataKind { - RS_KIND_USER, - - RS_KIND_PIXEL_L = 7, - RS_KIND_PIXEL_A, - RS_KIND_PIXEL_LA, - RS_KIND_PIXEL_RGB, - RS_KIND_PIXEL_RGBA, -}; - -enum RsSamplerParam { - RS_SAMPLER_MIN_FILTER, - RS_SAMPLER_MAG_FILTER, - RS_SAMPLER_WRAP_S, - RS_SAMPLER_WRAP_T, - RS_SAMPLER_WRAP_R, - RS_SAMPLER_ANISO -}; - -enum RsSamplerValue { - RS_SAMPLER_NEAREST, - RS_SAMPLER_LINEAR, - RS_SAMPLER_LINEAR_MIP_LINEAR, - RS_SAMPLER_WRAP, - RS_SAMPLER_CLAMP, - RS_SAMPLER_LINEAR_MIP_NEAREST, -}; - -enum RsTextureTarget { - RS_TEXTURE_2D, - RS_TEXTURE_CUBE -}; - -enum RsDimension { - RS_DIMENSION_X, - RS_DIMENSION_Y, - RS_DIMENSION_Z, - RS_DIMENSION_LOD, - RS_DIMENSION_FACE, - - RS_DIMENSION_ARRAY_0 = 100, - RS_DIMENSION_ARRAY_1, - RS_DIMENSION_ARRAY_2, - RS_DIMENSION_ARRAY_3, - RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3 -}; - -enum RsDepthFunc { - 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 -}; - -enum RsBlendSrcFunc { - 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 -}; - -enum RsBlendDstFunc { - 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 -}; - -enum RsTexEnvMode { - RS_TEX_ENV_MODE_NONE, - RS_TEX_ENV_MODE_REPLACE, - RS_TEX_ENV_MODE_MODULATE, - RS_TEX_ENV_MODE_DECAL -}; - -enum RsProgramParam { - RS_PROGRAM_PARAM_INPUT, - RS_PROGRAM_PARAM_OUTPUT, - RS_PROGRAM_PARAM_CONSTANT, - RS_PROGRAM_PARAM_TEXTURE_TYPE, -}; - -enum RsPrimitive { - RS_PRIMITIVE_POINT, - RS_PRIMITIVE_LINE, - RS_PRIMITIVE_LINE_STRIP, - RS_PRIMITIVE_TRIANGLE, - RS_PRIMITIVE_TRIANGLE_STRIP, - RS_PRIMITIVE_TRIANGLE_FAN -}; - -enum RsError { - RS_ERROR_NONE = 0, - RS_ERROR_BAD_SHADER = 1, - RS_ERROR_BAD_SCRIPT = 2, - RS_ERROR_BAD_VALUE = 3, - RS_ERROR_OUT_OF_MEMORY = 4, - RS_ERROR_DRIVER = 5, - - RS_ERROR_FATAL_UNKNOWN = 0x1000, - RS_ERROR_FATAL_DRIVER = 0x1001, - RS_ERROR_FATAL_PROGRAM_LINK = 0x1002 -}; - -enum RsAnimationInterpolation { - RS_ANIMATION_INTERPOLATION_STEP, - RS_ANIMATION_INTERPOLATION_LINEAR, - RS_ANIMATION_INTERPOLATION_BEZIER, - RS_ANIMATION_INTERPOLATION_CARDINAL, - RS_ANIMATION_INTERPOLATION_HERMITE, - RS_ANIMATION_INTERPOLATION_BSPLINE -}; - -enum RsAnimationEdge { - RS_ANIMATION_EDGE_UNDEFINED, - RS_ANIMATION_EDGE_CONSTANT, - RS_ANIMATION_EDGE_GRADIENT, - RS_ANIMATION_EDGE_CYCLE, - RS_ANIMATION_EDGE_OSCILLATE, - RS_ANIMATION_EDGE_CYLE_RELATIVE -}; - -enum RsA3DClassID { - RS_A3D_CLASS_ID_UNKNOWN, - RS_A3D_CLASS_ID_MESH, - RS_A3D_CLASS_ID_TYPE, - RS_A3D_CLASS_ID_ELEMENT, - RS_A3D_CLASS_ID_ALLOCATION, - RS_A3D_CLASS_ID_PROGRAM_VERTEX, - RS_A3D_CLASS_ID_PROGRAM_RASTER, - RS_A3D_CLASS_ID_PROGRAM_FRAGMENT, - RS_A3D_CLASS_ID_PROGRAM_STORE, - RS_A3D_CLASS_ID_SAMPLER, - RS_A3D_CLASS_ID_ANIMATION, - RS_A3D_CLASS_ID_ADAPTER_1D, - RS_A3D_CLASS_ID_ADAPTER_2D, - RS_A3D_CLASS_ID_SCRIPT_C -}; - -enum RsCullMode { - RS_CULL_BACK, - RS_CULL_FRONT, - RS_CULL_NONE -}; - -typedef struct { - RsA3DClassID classID; - const char* objectName; -} RsFileIndexEntry; - -// Script to Script -typedef struct { - uint32_t xStart; - uint32_t xEnd; - uint32_t yStart; - uint32_t yEnd; - uint32_t zStart; - uint32_t zEnd; - uint32_t arrayStart; - uint32_t arrayEnd; - -} RsScriptCall; - +// // A3D loading and object update code. // Should only be called at object creation, not thread safe RsObjectBase rsaFileA3DGetEntryByIndex(RsContext, uint32_t idx, RsFile); diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h new file mode 100644 index 0000000..4e1ac88 --- /dev/null +++ b/libs/rs/RenderScriptDefines.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2007 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 RENDER_SCRIPT_DEFINES_H +#define RENDER_SCRIPT_DEFINES_H + +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +////////////////////////////////////////////////////// +// + +typedef void * RsAsyncVoidPtr; + +typedef void * RsAdapter1D; +typedef void * RsAdapter2D; +typedef void * RsAllocation; +typedef void * RsAnimation; +typedef void * RsContext; +typedef void * RsDevice; +typedef void * RsElement; +typedef void * RsFile; +typedef void * RsFont; +typedef void * RsSampler; +typedef void * RsScript; +typedef void * RsMesh; +typedef void * RsType; +typedef void * RsObjectBase; + +typedef void * RsProgram; +typedef void * RsProgramVertex; +typedef void * RsProgramFragment; +typedef void * RsProgramStore; +typedef void * RsProgramRaster; + +typedef void (* RsBitmapCallback_t)(void *); + +enum RsDeviceParam { + RS_DEVICE_PARAM_FORCE_SOFTWARE_GL, + RS_DEVICE_PARAM_COUNT +}; + +typedef struct { + uint32_t colorMin; + uint32_t colorPref; + uint32_t alphaMin; + uint32_t alphaPref; + uint32_t depthMin; + uint32_t depthPref; + uint32_t stencilMin; + uint32_t stencilPref; + uint32_t samplesMin; + uint32_t samplesPref; + float samplesQ; +} RsSurfaceConfig; + +enum RsMessageToClientType { + RS_MESSAGE_TO_CLIENT_NONE = 0, + RS_MESSAGE_TO_CLIENT_EXCEPTION = 1, + RS_MESSAGE_TO_CLIENT_RESIZE = 2, + RS_MESSAGE_TO_CLIENT_ERROR = 3, + RS_MESSAGE_TO_CLIENT_USER = 4 +}; + +enum RsAllocationUsageType { + RS_ALLOCATION_USAGE_SCRIPT = 0x0001, + RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE = 0x0002, + RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004, + RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008, + + RS_ALLOCATION_USAGE_ALL = 0x000F +}; + +enum RsAllocationMipmapControl { + RS_ALLOCATION_MIPMAP_NONE = 0, + RS_ALLOCATION_MIPMAP_FULL = 1, + RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE = 2 +}; + +enum RsAllocationCubemapFace { + RS_ALLOCATION_CUBMAP_FACE_POSITVE_X = 0, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_X = 1, + RS_ALLOCATION_CUBMAP_FACE_POSITVE_Y = 2, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Y = 3, + RS_ALLOCATION_CUBMAP_FACE_POSITVE_Z = 4, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Z = 5 +}; + +enum RsDataType { + RS_TYPE_NONE, + RS_TYPE_FLOAT_16, + RS_TYPE_FLOAT_32, + 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, +}; + +enum RsDataKind { + RS_KIND_USER, + + RS_KIND_PIXEL_L = 7, + RS_KIND_PIXEL_A, + RS_KIND_PIXEL_LA, + RS_KIND_PIXEL_RGB, + RS_KIND_PIXEL_RGBA, +}; + +enum RsSamplerParam { + RS_SAMPLER_MIN_FILTER, + RS_SAMPLER_MAG_FILTER, + RS_SAMPLER_WRAP_S, + RS_SAMPLER_WRAP_T, + RS_SAMPLER_WRAP_R, + RS_SAMPLER_ANISO +}; + +enum RsSamplerValue { + RS_SAMPLER_NEAREST, + RS_SAMPLER_LINEAR, + RS_SAMPLER_LINEAR_MIP_LINEAR, + RS_SAMPLER_WRAP, + RS_SAMPLER_CLAMP, + RS_SAMPLER_LINEAR_MIP_NEAREST, +}; + +enum RsTextureTarget { + RS_TEXTURE_2D, + RS_TEXTURE_CUBE +}; + +enum RsDimension { + RS_DIMENSION_X, + RS_DIMENSION_Y, + RS_DIMENSION_Z, + RS_DIMENSION_LOD, + RS_DIMENSION_FACE, + + RS_DIMENSION_ARRAY_0 = 100, + RS_DIMENSION_ARRAY_1, + RS_DIMENSION_ARRAY_2, + RS_DIMENSION_ARRAY_3, + RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3 +}; + +enum RsDepthFunc { + 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 +}; + +enum RsBlendSrcFunc { + 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 +}; + +enum RsBlendDstFunc { + 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 +}; + +enum RsTexEnvMode { + RS_TEX_ENV_MODE_NONE, + RS_TEX_ENV_MODE_REPLACE, + RS_TEX_ENV_MODE_MODULATE, + RS_TEX_ENV_MODE_DECAL +}; + +enum RsProgramParam { + RS_PROGRAM_PARAM_INPUT, + RS_PROGRAM_PARAM_OUTPUT, + RS_PROGRAM_PARAM_CONSTANT, + RS_PROGRAM_PARAM_TEXTURE_TYPE, +}; + +enum RsPrimitive { + RS_PRIMITIVE_POINT, + RS_PRIMITIVE_LINE, + RS_PRIMITIVE_LINE_STRIP, + RS_PRIMITIVE_TRIANGLE, + RS_PRIMITIVE_TRIANGLE_STRIP, + RS_PRIMITIVE_TRIANGLE_FAN +}; + +enum RsError { + RS_ERROR_NONE = 0, + RS_ERROR_BAD_SHADER = 1, + RS_ERROR_BAD_SCRIPT = 2, + RS_ERROR_BAD_VALUE = 3, + RS_ERROR_OUT_OF_MEMORY = 4, + RS_ERROR_DRIVER = 5, + + RS_ERROR_FATAL_UNKNOWN = 0x1000, + RS_ERROR_FATAL_DRIVER = 0x1001, + RS_ERROR_FATAL_PROGRAM_LINK = 0x1002 +}; + +enum RsAnimationInterpolation { + RS_ANIMATION_INTERPOLATION_STEP, + RS_ANIMATION_INTERPOLATION_LINEAR, + RS_ANIMATION_INTERPOLATION_BEZIER, + RS_ANIMATION_INTERPOLATION_CARDINAL, + RS_ANIMATION_INTERPOLATION_HERMITE, + RS_ANIMATION_INTERPOLATION_BSPLINE +}; + +enum RsAnimationEdge { + RS_ANIMATION_EDGE_UNDEFINED, + RS_ANIMATION_EDGE_CONSTANT, + RS_ANIMATION_EDGE_GRADIENT, + RS_ANIMATION_EDGE_CYCLE, + RS_ANIMATION_EDGE_OSCILLATE, + RS_ANIMATION_EDGE_CYLE_RELATIVE +}; + +enum RsA3DClassID { + RS_A3D_CLASS_ID_UNKNOWN, + RS_A3D_CLASS_ID_MESH, + RS_A3D_CLASS_ID_TYPE, + RS_A3D_CLASS_ID_ELEMENT, + RS_A3D_CLASS_ID_ALLOCATION, + RS_A3D_CLASS_ID_PROGRAM_VERTEX, + RS_A3D_CLASS_ID_PROGRAM_RASTER, + RS_A3D_CLASS_ID_PROGRAM_FRAGMENT, + RS_A3D_CLASS_ID_PROGRAM_STORE, + RS_A3D_CLASS_ID_SAMPLER, + RS_A3D_CLASS_ID_ANIMATION, + RS_A3D_CLASS_ID_ADAPTER_1D, + RS_A3D_CLASS_ID_ADAPTER_2D, + RS_A3D_CLASS_ID_SCRIPT_C +}; + +enum RsCullMode { + RS_CULL_BACK, + RS_CULL_FRONT, + RS_CULL_NONE +}; + +typedef struct { + RsA3DClassID classID; + const char* objectName; +} RsFileIndexEntry; + +// Script to Script +typedef struct { + uint32_t xStart; + uint32_t xEnd; + uint32_t yStart; + uint32_t yEnd; + uint32_t zStart; + uint32_t zEnd; + uint32_t arrayStart; + uint32_t arrayEnd; + +} RsScriptCall; + +#ifdef __cplusplus +}; +#endif + +#endif // RENDER_SCRIPT_DEFINES_H + + + + diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp new file mode 100644 index 0000000..6c5a55b --- /dev/null +++ b/libs/rs/driver/rsdBcc.cpp @@ -0,0 +1,549 @@ +/* + * 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 "rsdCore.h" +#include "rsdBcc.h" + +#include "rsContext.h" +#include "rsScriptC.h" + +#include "utils/Timers.h" +#include "utils/StopWatch.h" +extern "C" { +#include "libdex/ZipArchive.h" +} + + +using namespace android; +using namespace android::renderscript; + +struct DrvScript { + int (*mRoot)(); + void (*mInit)(); + + BCCScriptRef mBccScript; + + uint32_t mInvokeFunctionCount; + InvokeFunc_t *mInvokeFunctions; + uint32_t mFieldCount; + void ** mFieldAddress; + bool * mFieldIsObject; + + const uint8_t * mScriptText; + uint32_t mScriptTextLength; + + //uint32_t * mObjectSlots; + //uint32_t mObjectSlotCount; + + uint32_t mPragmaCount; + const char ** mPragmaKeys; + const char ** mPragmaValues; + +}; + +static Script * setTLS(Script *sc) { + ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); + rsAssert(tls); + Script *old = tls->mScript; + tls->mScript = sc; + return old; +} + + +// Input: cacheDir +// Input: resName +// Input: extName +// +// Note: cacheFile = resName + extName +// +// Output: Returns cachePath == cacheDir + cacheFile +static char *genCacheFileName(const char *cacheDir, + const char *resName, + const char *extName) { + char cachePath[512]; + char cacheFile[sizeof(cachePath)]; + const size_t kBufLen = sizeof(cachePath) - 1; + + cacheFile[0] = '\0'; + // Note: resName today is usually something like + // "/com.android.fountain:raw/fountain" + if (resName[0] != '/') { + // Get the absolute path of the raw/***.bc file. + + // Generate the absolute path. This doesn't do everything it + // should, e.g. if resName is "./out/whatever" it doesn't crunch + // the leading "./" out because this if-block is not triggered, + // but it'll make do. + // + if (getcwd(cacheFile, kBufLen) == NULL) { + LOGE("Can't get CWD while opening raw/***.bc file\n"); + return NULL; + } + // Append "/" at the end of cacheFile so far. + strncat(cacheFile, "/", kBufLen); + } + + // cacheFile = resName + extName + // + strncat(cacheFile, resName, kBufLen); + if (extName != NULL) { + // TODO(srhines): strncat() is a bit dangerous + strncat(cacheFile, extName, kBufLen); + } + + // Turn the path into a flat filename by replacing + // any slashes after the first one with '@' characters. + char *cp = cacheFile + 1; + while (*cp != '\0') { + if (*cp == '/') { + *cp = '@'; + } + cp++; + } + + // Tack on the file name for the actual cache file path. + strncpy(cachePath, cacheDir, kBufLen); + strncat(cachePath, cacheFile, kBufLen); + + LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath); + return strdup(cachePath); +} + +bool rsdScriptInit(const Context *rsc, + ScriptC *script, + char const *resName, + char const *cacheDir, + uint8_t const *bitcode, + size_t bitcodeSize, + uint32_t flags, + RsHalSymbolLookupFunc lookupFunc) { + //LOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc); + + char *cachePath = NULL; + uint32_t objectSlotCount = 0; + + DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript)); + if (drv == NULL) { + return false; + } + script->mHal.drv = drv; + + drv->mBccScript = bccCreateScript(); + script->mHal.info.isThreadable = true; + drv->mScriptText = bitcode; + drv->mScriptTextLength = bitcodeSize; + + //LOGE("mBccScript %p", script->mBccScript); + + if (bccRegisterSymbolCallback(drv->mBccScript, lookupFunc, script) != 0) { + LOGE("bcc: FAILS to register symbol callback"); + goto error; + } + + if (bccReadBC(drv->mBccScript, + resName, + (char const *)drv->mScriptText, + drv->mScriptTextLength, 0) != 0) { + LOGE("bcc: FAILS to read bitcode"); + return NULL; + } + +#if 1 + if (bccLinkFile(drv->mBccScript, "/system/lib/libclcore.bc", 0) != 0) { + LOGE("bcc: FAILS to link bitcode"); + return NULL; + } +#endif + cachePath = genCacheFileName(cacheDir, resName, ".oBCC"); + + if (bccPrepareExecutable(drv->mBccScript, cachePath, 0) != 0) { + LOGE("bcc: FAILS to prepare executable"); + return NULL; + } + + free(cachePath); + + drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root")); + drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init")); + + drv->mInvokeFunctionCount = bccGetExportFuncCount(drv->mBccScript); + if (drv->mInvokeFunctionCount <= 0) + drv->mInvokeFunctions = NULL; + else { + drv->mInvokeFunctions = (InvokeFunc_t*) calloc(drv->mInvokeFunctionCount, sizeof(InvokeFunc_t)); + bccGetExportFuncList(drv->mBccScript, drv->mInvokeFunctionCount, (void **) drv->mInvokeFunctions); + } + + drv->mFieldCount = bccGetExportVarCount(drv->mBccScript); + if (drv->mFieldCount <= 0) { + drv->mFieldAddress = NULL; + drv->mFieldIsObject = NULL; + } else { + drv->mFieldAddress = (void **) calloc(drv->mFieldCount, sizeof(void *)); + drv->mFieldIsObject = (bool *) calloc(drv->mFieldCount, sizeof(bool)); + bccGetExportVarList(drv->mBccScript, drv->mFieldCount, (void **) drv->mFieldAddress); + } + + objectSlotCount = bccGetObjectSlotCount(drv->mBccScript); + if (objectSlotCount) { + uint32_t * slots = new uint32_t[objectSlotCount]; + bccGetObjectSlotList(drv->mBccScript, objectSlotCount, slots); + for (uint32_t ct=0; ct < objectSlotCount; ct++) { + drv->mFieldIsObject[slots[ct]] = true; + } + delete [] slots; + } + + uint32_t mPragmaCount; + const char ** mPragmaKeys; + const char ** mPragmaValues; + + const static int pragmaMax = 16; + drv->mPragmaCount = bccGetPragmaCount(drv->mBccScript); + if (drv->mPragmaCount <= 0) { + drv->mPragmaKeys = NULL; + drv->mPragmaValues = NULL; + } else { + drv->mPragmaKeys = (const char **) calloc(drv->mFieldCount, sizeof(const char *)); + drv->mPragmaValues = (const char **) calloc(drv->mFieldCount, sizeof(const char *)); + bccGetPragmaList(drv->mBccScript, drv->mPragmaCount, drv->mPragmaKeys, drv->mPragmaValues); + } + + + + // Copy info over to runtime + script->mHal.info.exportedFunctionCount = drv->mInvokeFunctionCount; + script->mHal.info.exportedVariableCount = drv->mFieldCount; + script->mHal.info.exportedPragmaCount = drv->mPragmaCount; + script->mHal.info.exportedPragmaKeyList = drv->mPragmaKeys; + script->mHal.info.exportedPragmaValueList = drv->mPragmaValues; + script->mHal.info.root = drv->mRoot; + + + return true; + +error: + + free(drv); + return false; + +} + +typedef struct { + Context *rsc; + Script *script; + const Allocation * ain; + Allocation * aout; + const void * usr; + + uint32_t mSliceSize; + volatile int mSliceNum; + + const uint8_t *ptrIn; + uint32_t eStrideIn; + uint8_t *ptrOut; + uint32_t eStrideOut; + + uint32_t xStart; + uint32_t xEnd; + uint32_t yStart; + uint32_t yEnd; + uint32_t zStart; + uint32_t zEnd; + uint32_t arrayStart; + uint32_t arrayEnd; + + uint32_t dimX; + uint32_t dimY; + uint32_t dimZ; + uint32_t dimArray; +} MTLaunchStruct; +typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); + +static void wc_xy(void *usr, uint32_t idx) { + MTLaunchStruct *mtls = (MTLaunchStruct *)usr; + + while (1) { + uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); + uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize; + uint32_t yEnd = yStart + mtls->mSliceSize; + yEnd = rsMin(yEnd, mtls->yEnd); + if (yEnd <= yStart) { + return; + } + + //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); + //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); + for (uint32_t y = yStart; y < yEnd; y++) { + uint32_t offset = mtls->dimX * y; + uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset); + const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset); + + for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) { + ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0); + xPtrIn += mtls->eStrideIn; + xPtrOut += mtls->eStrideOut; + } + } + } +} + +static void wc_x(void *usr, uint32_t idx) { + MTLaunchStruct *mtls = (MTLaunchStruct *)usr; + + while (1) { + uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); + uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize; + uint32_t xEnd = xStart + mtls->mSliceSize; + xEnd = rsMin(xEnd, mtls->xEnd); + if (xEnd <= xStart) { + return; + } + + //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); + //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); + uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart); + const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart); + for (uint32_t x = xStart; x < xEnd; x++) { + ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0); + xPtrIn += mtls->eStrideIn; + xPtrOut += mtls->eStrideOut; + } + } +} + +void rsdScriptInvokeForEach(const Context *rsc, + Script *s, + const Allocation * ain, + Allocation * aout, + const void * usr, + uint32_t usrLen, + const RsScriptCall *sc) { + + RsHal * dc = (RsHal *)rsc->mHal.drv; + + MTLaunchStruct mtls; + memset(&mtls, 0, sizeof(mtls)); + + if (ain) { + mtls.dimX = ain->getType()->getDimX(); + mtls.dimY = ain->getType()->getDimY(); + mtls.dimZ = ain->getType()->getDimZ(); + //mtls.dimArray = ain->getType()->getDimArray(); + } else if (aout) { + mtls.dimX = aout->getType()->getDimX(); + mtls.dimY = aout->getType()->getDimY(); + mtls.dimZ = aout->getType()->getDimZ(); + //mtls.dimArray = aout->getType()->getDimArray(); + } else { + rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations"); + return; + } + + if (!sc || (sc->xEnd == 0)) { + mtls.xEnd = mtls.dimX; + } else { + rsAssert(sc->xStart < mtls.dimX); + rsAssert(sc->xEnd <= mtls.dimX); + rsAssert(sc->xStart < sc->xEnd); + mtls.xStart = rsMin(mtls.dimX, sc->xStart); + mtls.xEnd = rsMin(mtls.dimX, sc->xEnd); + if (mtls.xStart >= mtls.xEnd) return; + } + + if (!sc || (sc->yEnd == 0)) { + mtls.yEnd = mtls.dimY; + } else { + rsAssert(sc->yStart < mtls.dimY); + rsAssert(sc->yEnd <= mtls.dimY); + rsAssert(sc->yStart < sc->yEnd); + mtls.yStart = rsMin(mtls.dimY, sc->yStart); + mtls.yEnd = rsMin(mtls.dimY, sc->yEnd); + if (mtls.yStart >= mtls.yEnd) return; + } + + mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd); + mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd); + mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd); + mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd); + + rsAssert(ain->getType()->getDimZ() == 0); + + Context *mrsc = (Context *)rsc; + Script * oldTLS = setTLS(s); + + mtls.rsc = mrsc; + mtls.ain = ain; + mtls.aout = aout; + mtls.script = s; + mtls.usr = usr; + mtls.mSliceSize = 10; + mtls.mSliceNum = 0; + + mtls.ptrIn = NULL; + mtls.eStrideIn = 0; + if (ain) { + mtls.ptrIn = (const uint8_t *)ain->getPtr(); + mtls.eStrideIn = ain->getType()->getElementSizeBytes(); + } + + mtls.ptrOut = NULL; + mtls.eStrideOut = 0; + if (aout) { + mtls.ptrOut = (uint8_t *)aout->getPtr(); + mtls.eStrideOut = aout->getType()->getElementSizeBytes(); + } + + if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable) { + if (mtls.dimY > 1) { + rsdLaunchThreads(mrsc, wc_xy, &mtls); + } else { + rsdLaunchThreads(mrsc, wc_x, &mtls); + } + + //LOGE("launch 1"); + } else { + //LOGE("launch 3"); + for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) { + for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) { + for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) { + uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar + + mtls.dimX * mtls.dimY * z + + mtls.dimX * y; + uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset); + const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset); + + for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) { + ((rs_t)s->mHal.info.root) (xPtrIn, xPtrOut, usr, x, y, z, ar); + xPtrIn += mtls.eStrideIn; + xPtrOut += mtls.eStrideOut; + } + } + } + } + } + + setTLS(oldTLS); +} + + +int rsdScriptInvokeRoot(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + Script * oldTLS = setTLS(script); + int ret = drv->mRoot(); + setTLS(oldTLS); + + return ret; +} + +void rsdScriptInvokeInit(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + if (drv->mInit) { + drv->mInit(); + } +} + + +void rsdScriptInvokeFunction(const Context *dc, Script *script, + uint32_t slot, + const void *params, + size_t paramLength) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //LOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength); + + Script * oldTLS = setTLS(script); + ((void (*)(const void *, uint32_t)) + drv->mInvokeFunctions[slot])(params, paramLength); + setTLS(oldTLS); +} + +void rsdScriptSetGlobalVar(const Context *dc, const Script *script, + uint32_t slot, void *data, size_t dataLength) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(!script->mFieldIsObject[slot]); + //LOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + memcpy(destPtr, data, dataLength); +} + +void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, void *data) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(!script->mFieldIsObject[slot]); + //LOGE("setGlobalBind %p %p %i %p", dc, script, slot, data); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + memcpy(destPtr, &data, sizeof(void *)); +} + +void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slot, ObjectBase *data) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(script->mFieldIsObject[slot]); + //LOGE("setGlobalObj %p %p %i %p", dc, script, slot, data); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + rsiSetObject((ObjectBase **)destPtr, data); +} + +void rsdScriptDestroy(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + if (drv->mFieldAddress) { + for (size_t ct=0; ct < drv->mFieldCount; ct++) { + if (drv->mFieldIsObject[ct]) { + // The field address can be NULL if the script-side has + // optimized the corresponding global variable away. + if (drv->mFieldAddress[ct]) { + rsiClearObject((ObjectBase **)drv->mFieldAddress[ct]); + } + } + } + delete [] drv->mFieldAddress; + delete [] drv->mFieldIsObject; + drv->mFieldAddress = NULL; + drv->mFieldIsObject = NULL; + drv->mFieldCount = 0; + } + + if (drv->mInvokeFunctions) { + delete [] drv->mInvokeFunctions; + drv->mInvokeFunctions = NULL; + drv->mInvokeFunctionCount = 0; + } + free(drv); + script->mHal.drv = NULL; + +} + + diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h new file mode 100644 index 0000000..6723a36 --- /dev/null +++ b/libs/rs/driver/rsdBcc.h @@ -0,0 +1,70 @@ +/* + * 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 RSD_BCC_H +#define RSD_BCC_H + +#include <rs_hal.h> + + +bool rsdScriptInit(const android::renderscript::Context *, android::renderscript::ScriptC *, + char const *resName, char const *cacheDir, + uint8_t const *bitcode, size_t bitcodeSize, + uint32_t flags, android::renderscript::RsHalSymbolLookupFunc lookupFunc); +void rsdScriptInvokeFunction(const android::renderscript::Context *dc, + android::renderscript::Script *script, + uint32_t slot, + const void *params, + size_t paramLength); + +void rsdScriptInvokeForEach(const android::renderscript::Context *rsc, + android::renderscript::Script *s, + const android::renderscript::Allocation * ain, + android::renderscript::Allocation * aout, + const void * usr, + uint32_t usrLen, + const RsScriptCall *sc); + +int rsdScriptInvokeRoot(const android::renderscript::Context *dc, + android::renderscript::Script *script); +void rsdScriptInvokeInit(const android::renderscript::Context *dc, + android::renderscript::Script *script); + +void rsdScriptSetGlobalVar(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, void *data, size_t dataLen); +void rsdScriptSetGlobalBind(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, void *data); +void rsdScriptSetGlobalObj(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, android::renderscript::ObjectBase *data); + +void rsdScriptSetGlobal(const android::renderscript::Context *dc, + const android::renderscript::Script *script, + uint32_t slot, + void *data, + size_t dataLength); +void rsdScriptGetGlobal(const android::renderscript::Context *dc, + const android::renderscript::Script *script, + uint32_t slot, + void *data, + size_t dataLength); +void rsdScriptDestroy(const android::renderscript::Context *dc, + android::renderscript::Script *script); + + +#endif diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp new file mode 100644 index 0000000..6546110 --- /dev/null +++ b/libs/rs/driver/rsdCore.cpp @@ -0,0 +1,186 @@ +/* + * 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 "rsdCore.h" +#include "rsdBcc.h" + +#include <malloc.h> +#include "rsContext.h" + +#include <sys/types.h> +#include <sys/resource.h> +#include <sched.h> +#include <cutils/properties.h> +#include <cutils/sched_policy.h> +#include <sys/syscall.h> +#include <string.h> + +using namespace android; +using namespace android::renderscript; + +static void Shutdown(Context *rsc); +static void SetPriority(const Context *rsc, int32_t priority); + +static RsdHalFunctions FunctionTable = { + Shutdown, + NULL, + SetPriority, + { + rsdScriptInit, + rsdScriptInvokeFunction, + rsdScriptInvokeRoot, + rsdScriptInvokeForEach, + rsdScriptInvokeInit, + rsdScriptSetGlobalVar, + rsdScriptSetGlobalBind, + rsdScriptSetGlobalObj, + rsdScriptDestroy + } +}; + + + +static void * HelperThreadProc(void *vrsc) { + Context *rsc = static_cast<Context *>(vrsc); + RsHal *dc = (RsHal *)rsc->mHal.drv; + + + uint32_t idx = (uint32_t)android_atomic_inc(&dc->mWorkers.mLaunchCount); + + //LOGV("RS helperThread starting %p idx=%i", rsc, idx); + + dc->mWorkers.mLaunchSignals[idx].init(); + dc->mWorkers.mNativeThreadId[idx] = gettid(); + +#if 0 + typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t; + cpu_set_t cpuset; + memset(&cpuset, 0, sizeof(cpuset)); + cpuset.bits[idx / 64] |= 1ULL << (idx % 64); + int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx], + sizeof(cpuset), &cpuset); + LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret)); +#endif + + int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct); + if (status) { + LOGE("pthread_setspecific %i", status); + } + + while (!dc->mExit) { + dc->mWorkers.mLaunchSignals[idx].wait(); + if (dc->mWorkers.mLaunchCallback) { + dc->mWorkers.mLaunchCallback(dc->mWorkers.mLaunchData, idx); + } + android_atomic_dec(&dc->mWorkers.mRunningCount); + dc->mWorkers.mCompleteSignal.set(); + } + + //LOGV("RS helperThread exited %p idx=%i", rsc, idx); + return NULL; +} + +void rsdLaunchThreads(Context *rsc, WorkerCallback_t cbk, void *data) { + RsHal *dc = (RsHal *)rsc->mHal.drv; + + dc->mWorkers.mLaunchData = data; + dc->mWorkers.mLaunchCallback = cbk; + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + dc->mWorkers.mLaunchSignals[ct].set(); + } + while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) { + dc->mWorkers.mCompleteSignal.wait(); + } +} + +bool rsdHalInit(Context *rsc, uint32_t version_major, uint32_t version_minor) { + rsc->mHal.funcs = FunctionTable; + + RsHal *dc = (RsHal *)calloc(1, sizeof(RsHal)); + if (!dc) { + LOGE("Calloc for driver hal failed."); + return false; + } + rsc->mHal.drv = dc; + + + int cpu = sysconf(_SC_NPROCESSORS_ONLN); + LOGV("RS Launching thread(s), reported CPU count %i", cpu); + if (cpu < 2) cpu = 0; + + dc->mWorkers.mCount = (uint32_t)cpu; + dc->mWorkers.mThreadId = (pthread_t *) calloc(dc->mWorkers.mCount, sizeof(pthread_t)); + dc->mWorkers.mNativeThreadId = (pid_t *) calloc(dc->mWorkers.mCount, sizeof(pid_t)); + dc->mWorkers.mLaunchSignals = new Signal[dc->mWorkers.mCount]; + dc->mWorkers.mLaunchCallback = NULL; + + dc->mWorkers.mCompleteSignal.init(); + + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + android_atomic_release_store(0, &dc->mWorkers.mLaunchCount); + + int status; + pthread_attr_t threadAttr; + status = pthread_attr_init(&threadAttr); + if (status) { + LOGE("Failed to init thread attribute."); + return false; + } + + for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) { + status = pthread_create(&dc->mWorkers.mThreadId[ct], &threadAttr, HelperThreadProc, rsc); + if (status) { + dc->mWorkers.mCount = ct; + LOGE("Created fewer than expected number of RS threads."); + break; + } + } + while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) { + usleep(100); + } + + pthread_attr_destroy(&threadAttr); + return true; +} + + +void SetPriority(const Context *rsc, int32_t priority) { + RsHal *dc = (RsHal *)rsc->mHal.drv; + for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) { + setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority); + } +} + +void Shutdown(Context *rsc) { + RsHal *dc = (RsHal *)rsc->mHal.drv; + + dc->mExit = true; + dc->mWorkers.mLaunchData = NULL; + dc->mWorkers.mLaunchCallback = NULL; + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + dc->mWorkers.mLaunchSignals[ct].set(); + } + int status; + void *res; + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + status = pthread_join(dc->mWorkers.mThreadId[ct], &res); + } + rsAssert(android_atomic_acquire_load(&dc->mWorkers.mRunningCount) == 0); +} + + diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h new file mode 100644 index 0000000..02b2fbc --- /dev/null +++ b/libs/rs/driver/rsdCore.h @@ -0,0 +1,55 @@ +/* + * 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_CORE_H +#define RSD_CORE_H + +#include <rs_hal.h> +#include <bcc/bcc.h> + +#include "rsMutex.h" +#include "rsSignal.h" + + +typedef void (* InvokeFunc_t)(void); +typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); + +typedef struct RsHalRec { + uint32_t version_major; + uint32_t version_minor; + + struct Workers { + volatile int mRunningCount; + volatile int mLaunchCount; + uint32_t mCount; + pthread_t *mThreadId; + pid_t *mNativeThreadId; + android::renderscript::Signal mCompleteSignal; + + android::renderscript::Signal *mLaunchSignals; + WorkerCallback_t mLaunchCallback; + void *mLaunchData; + }; + Workers mWorkers; + bool mExit; +} RsHal; + + + +void rsdLaunchThreads(android::renderscript::Context *rsc, WorkerCallback_t cbk, void *data); + +#endif + diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index 7e23cec..bbb6200 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -181,10 +181,6 @@ ScriptBindAllocation { } -ScriptCBegin { - } - - ScriptSetTimeZone { param RsScript s param const char * timeZone @@ -246,15 +242,11 @@ ScriptSetVarV { } -ScriptCSetText { - param const char * text - param uint32_t length - } - ScriptCCreate { - param const char * packageName param const char * resName param const char * cacheDir + param const char * text + param uint32_t length ret RsScript } diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index ec03a15..b8ddb0b 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -29,21 +29,22 @@ Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages, : ObjectBase(rsc) { init(rsc, type); - mUsageFlags = usages; - mMipmapControl = mc; + mHal.state.usageFlags = usages; + mHal.state.mipmapControl = mc; allocScriptMemory(); - if (mType->getElement()->getHasReferences()) { - memset(mPtr, 0, mType->getSizeBytes()); + if (mHal.state.type->getElement()->getHasReferences()) { + memset(mHal.state.mallocPtr, 0, mHal.state.type->getSizeBytes()); } - if (!mPtr) { + if (!mHal.state.mallocPtr) { LOGE("Allocation::Allocation, alloc failure"); } } void Allocation::init(Context *rsc, const Type *type) { - mPtr = NULL; + memset(&mHal, 0, sizeof(mHal)); + mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE; mCpuWrite = false; mCpuRead = false; @@ -52,8 +53,6 @@ void Allocation::init(Context *rsc, const Type *type) { mReadWriteRatio = 0; mUpdateSize = 0; - mUsageFlags = 0; - mMipmapControl = RS_ALLOCATION_MIPMAP_NONE; mTextureID = 0; mBufferID = 0; @@ -62,16 +61,25 @@ void Allocation::init(Context *rsc, const Type *type) { mUserBitmapCallback = NULL; mUserBitmapCallbackData = NULL; - mType.set(type); - rsAssert(type); + mHal.state.type.set(type); + updateCache(); +} - mPtr = NULL; +void Allocation::updateCache() { + const Type *type = mHal.state.type.get(); + mHal.state.dimensionX = type->getDimX(); + mHal.state.dimensionY = type->getDimY(); + mHal.state.dimensionZ = type->getDimZ(); + mHal.state.hasFaces = type->getDimFaces(); + mHal.state.hasMipmaps = type->getDimLOD(); + mHal.state.elementSizeBytes = type->getElementSizeBytes(); + mHal.state.hasReferences = mHal.state.type->getElement()->getHasReferences(); } Allocation::~Allocation() { if (mUserBitmapCallback != NULL) { mUserBitmapCallback(mUserBitmapCallbackData); - mPtr = NULL; + mHal.state.mallocPtr = NULL; } freeScriptMemory(); #ifndef ANDROID_RS_SERIALIZE @@ -105,14 +113,14 @@ bool Allocation::fixAllocation() { } void Allocation::deferedUploadToTexture(const Context *rsc) { - mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE; + mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE; mUploadDefered = true; } uint32_t Allocation::getGLTarget() const { #ifndef ANDROID_RS_SERIALIZE if (getIsTexture()) { - if (mType->getDimFaces()) { + if (mHal.state.type->getDimFaces()) { return GL_TEXTURE_CUBE_MAP; } else { return GL_TEXTURE_2D; @@ -126,14 +134,14 @@ uint32_t Allocation::getGLTarget() const { } void Allocation::allocScriptMemory() { - rsAssert(!mPtr); - mPtr = malloc(mType->getSizeBytes()); + rsAssert(!mHal.state.mallocPtr); + mHal.state.mallocPtr = malloc(mHal.state.type->getSizeBytes()); } void Allocation::freeScriptMemory() { - if (mPtr) { - free(mPtr); - mPtr = NULL; + if (mHal.state.mallocPtr) { + free(mHal.state.mallocPtr); + mHal.state.mallocPtr = NULL; } } @@ -153,15 +161,15 @@ void Allocation::syncAll(Context *rsc, RsAllocationUsageType src) { void Allocation::uploadToTexture(const Context *rsc) { #ifndef ANDROID_RS_SERIALIZE - mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE; - GLenum type = mType->getElement()->getComponent().getGLType(); - GLenum format = mType->getElement()->getComponent().getGLFormat(); + mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE; + GLenum type = mHal.state.type->getElement()->getComponent().getGLType(); + GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat(); if (!type || !format) { return; } - if (!mPtr) { + if (!mHal.state.mallocPtr) { return; } @@ -184,7 +192,7 @@ void Allocation::uploadToTexture(const Context *rsc) { upload2DTexture(isFirstUpload); - if (!(mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT)) { + if (!(mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) { freeScriptMemory(); } @@ -207,14 +215,14 @@ void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h) { #ifndef ANDROID_RS_SERIALIZE - GLenum type = mType->getElement()->getComponent().getGLType(); - GLenum format = mType->getElement()->getComponent().getGLFormat(); + GLenum type = mHal.state.type->getElement()->getComponent().getGLType(); + GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat(); GLenum target = (GLenum)getGLTarget(); rsAssert(mTextureID); glBindTexture(target, mTextureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GLenum t = GL_TEXTURE_2D; - if (mType->getDimFaces()) { + if (mHal.state.hasFaces) { t = gFaceOrder[face]; } glTexSubImage2D(t, lod, xoff, yoff, w, h, format, type, ptr); @@ -223,57 +231,57 @@ void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff, void Allocation::upload2DTexture(bool isFirstUpload) { #ifndef ANDROID_RS_SERIALIZE - GLenum type = mType->getElement()->getComponent().getGLType(); - GLenum format = mType->getElement()->getComponent().getGLFormat(); + GLenum type = mHal.state.type->getElement()->getComponent().getGLType(); + GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat(); GLenum target = (GLenum)getGLTarget(); glBindTexture(target, mTextureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); uint32_t faceCount = 1; - if (mType->getDimFaces()) { + if (mHal.state.hasFaces) { faceCount = 6; } for (uint32_t face = 0; face < faceCount; face ++) { - for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) { - const uint8_t *p = (const uint8_t *)mPtr; - p += mType->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0); + for (uint32_t lod = 0; lod < mHal.state.type->getLODCount(); lod++) { + const uint8_t *p = (const uint8_t *)mHal.state.mallocPtr; + p += mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0); GLenum t = GL_TEXTURE_2D; - if (mType->getDimFaces()) { + if (mHal.state.hasFaces) { t = gFaceOrder[face]; } if (isFirstUpload) { glTexImage2D(t, lod, format, - mType->getLODDimX(lod), mType->getLODDimY(lod), + mHal.state.type->getLODDimX(lod), mHal.state.type->getLODDimY(lod), 0, format, type, p); } else { glTexSubImage2D(t, lod, 0, 0, - mType->getLODDimX(lod), mType->getLODDimY(lod), + mHal.state.type->getLODDimX(lod), mHal.state.type->getLODDimY(lod), format, type, p); } } } - if (mMipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) { + if (mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) { glGenerateMipmap(target); } #endif //ANDROID_RS_SERIALIZE } void Allocation::deferedUploadToBufferObject(const Context *rsc) { - mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; + mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; mUploadDefered = true; } void Allocation::uploadToBufferObject(const Context *rsc) { #ifndef ANDROID_RS_SERIALIZE - rsAssert(!mType->getDimY()); - rsAssert(!mType->getDimZ()); + rsAssert(!mHal.state.type->getDimY()); + rsAssert(!mHal.state.type->getDimZ()); - mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; + mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; if (!mBufferID) { glGenBuffers(1, &mBufferID); @@ -285,7 +293,7 @@ void Allocation::uploadToBufferObject(const Context *rsc) { } GLenum target = (GLenum)getGLTarget(); glBindBuffer(target, mBufferID); - glBufferData(target, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW); + glBufferData(target, mHal.state.type->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW); glBindBuffer(target, 0); rsc->checkError("Allocation::uploadToBufferObject"); #endif //ANDROID_RS_SERIALIZE @@ -298,23 +306,23 @@ void Allocation::uploadCheck(Context *rsc) { } void Allocation::read(void *data) { - memcpy(data, mPtr, mType->getSizeBytes()); + memcpy(data, mHal.state.mallocPtr, mHal.state.type->getSizeBytes()); } void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, uint32_t sizeBytes) { - uint32_t eSize = mType->getElementSizeBytes(); - uint8_t * ptr = static_cast<uint8_t *>(mPtr); + uint32_t eSize = mHal.state.type->getElementSizeBytes(); + uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr); ptr += eSize * xoff; uint32_t size = count * eSize; if (size != sizeBytes) { LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes); - mType->dumpLOGV("type info"); + mHal.state.type->dumpLOGV("type info"); return; } - if (mType->getElement()->getHasReferences()) { + if (mHal.state.hasReferences) { incRefs(data, count); decRefs(ptr, count); } @@ -326,9 +334,9 @@ void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod, void Allocation::data(Context *rsc, 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 eSize = mType->getElementSizeBytes(); + uint32_t eSize = mHal.state.elementSizeBytes; uint32_t lineSize = eSize * w; - uint32_t destW = mType->getDimX(); + uint32_t destW = mHal.state.dimensionX; //LOGE("data2d %p, %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes); @@ -338,14 +346,14 @@ void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, return; } - if (mPtr) { + if (mHal.state.mallocPtr) { const uint8_t *src = static_cast<const uint8_t *>(data); - uint8_t *dst = static_cast<uint8_t *>(mPtr); - dst += mType->getLODFaceOffset(lod, face, xoff, yoff); + uint8_t *dst = static_cast<uint8_t *>(mHal.state.mallocPtr); + dst += mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff); //LOGE(" %p %p %i ", dst, src, eSize); for (uint32_t line=yoff; line < (yoff+h); line++) { - if (mType->getElement()->getHasReferences()) { + if (mHal.state.hasReferences) { incRefs(src, w); decRefs(dst, w); } @@ -367,24 +375,24 @@ void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, void Allocation::elementData(Context *rsc, uint32_t x, const void *data, uint32_t cIdx, uint32_t sizeBytes) { - uint32_t eSize = mType->getElementSizeBytes(); - uint8_t * ptr = static_cast<uint8_t *>(mPtr); + uint32_t eSize = mHal.state.elementSizeBytes; + uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr); ptr += eSize * x; - if (cIdx >= mType->getElement()->getFieldCount()) { + if (cIdx >= mHal.state.type->getElement()->getFieldCount()) { LOGE("Error Allocation::subElementData component %i out of range.", cIdx); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range."); return; } - if (x >= mType->getDimX()) { + if (x >= mHal.state.dimensionX) { LOGE("Error Allocation::subElementData X offset %i out of range.", x); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range."); return; } - const Element * e = mType->getElement()->getField(cIdx); - ptr += mType->getElement()->getFieldOffsetBytes(cIdx); + const Element * e = mHal.state.type->getElement()->getField(cIdx); + ptr += mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); if (sizeBytes != e->getSizeBytes()) { LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes()); @@ -404,30 +412,30 @@ void Allocation::elementData(Context *rsc, uint32_t x, const void *data, void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y, const void *data, uint32_t cIdx, uint32_t sizeBytes) { - uint32_t eSize = mType->getElementSizeBytes(); - uint8_t * ptr = static_cast<uint8_t *>(mPtr); - ptr += eSize * (x + y * mType->getDimX()); + uint32_t eSize = mHal.state.elementSizeBytes; + uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr); + ptr += eSize * (x + y * mHal.state.dimensionX); - if (x >= mType->getDimX()) { + if (x >= mHal.state.dimensionX) { LOGE("Error Allocation::subElementData X offset %i out of range.", x); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range."); return; } - if (y >= mType->getDimY()) { + if (y >= mHal.state.dimensionY) { LOGE("Error Allocation::subElementData X offset %i out of range.", x); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range."); return; } - if (cIdx >= mType->getElement()->getFieldCount()) { + if (cIdx >= mHal.state.type->getElement()->getFieldCount()) { LOGE("Error Allocation::subElementData component %i out of range.", cIdx); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range."); return; } - const Element * e = mType->getElement()->getField(cIdx); - ptr += mType->getElement()->getFieldOffsetBytes(cIdx); + const Element * e = mHal.state.type->getElement()->getField(cIdx); + ptr += mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); if (sizeBytes != e->getSizeBytes()) { LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes()); @@ -468,15 +476,15 @@ void Allocation::dumpLOGV(const char *prefix) const { String8 s(prefix); s.append(" type "); - if (mType.get()) { - mType->dumpLOGV(s.string()); + if (mHal.state.type.get()) { + mHal.state.type->dumpLOGV(s.string()); } LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i", - prefix, mPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead); + prefix, mHal.state.mallocPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead); LOGV("%s allocation mUsageFlags=0x04%x, mMipmapControl=0x%04x, mTextureID=%i, mBufferID=%i", - prefix, mUsageFlags, mMipmapControl, mTextureID, mBufferID); + prefix, mHal.state.usageFlags, mHal.state.mipmapControl, mTextureID, mBufferID); } void Allocation::serialize(OStream *stream) const { @@ -488,13 +496,13 @@ void Allocation::serialize(OStream *stream) const { // First thing we need to serialize is the type object since it will be needed // to initialize the class - mType->serialize(stream); + mHal.state.type->serialize(stream); - uint32_t dataSize = mType->getSizeBytes(); + uint32_t dataSize = mHal.state.type->getSizeBytes(); // Write how much data we are storing stream->addU32(dataSize); // Now write the data - stream->addByteArray(mPtr, dataSize); + stream->addByteArray(mHal.state.mallocPtr, dataSize); } Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) { @@ -544,7 +552,7 @@ void Allocation::sendDirty() const { void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const { const uint8_t *p = static_cast<const uint8_t *>(ptr); - const Element *e = mType->getElement(); + const Element *e = mHal.state.type->getElement(); uint32_t stride = e->getSizeBytes(); p += stride * startOff; @@ -557,7 +565,7 @@ void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const { void Allocation::decRefs(const void *ptr, size_t ct, size_t startOff) const { const uint8_t *p = static_cast<const uint8_t *>(ptr); - const Element *e = mType->getElement(); + const Element *e = mHal.state.type->getElement(); uint32_t stride = e->getSizeBytes(); p += stride * startOff; @@ -572,24 +580,26 @@ void Allocation::copyRange1D(Context *rsc, const Allocation *src, int32_t srcOff } void Allocation::resize1D(Context *rsc, uint32_t dimX) { - Type *t = mType->cloneAndResize1D(rsc, dimX); + Type *t = mHal.state.type->cloneAndResize1D(rsc, dimX); - uint32_t oldDimX = mType->getDimX(); + uint32_t oldDimX = mHal.state.dimensionX; if (dimX == oldDimX) { return; } if (dimX < oldDimX) { - decRefs(mPtr, oldDimX - dimX, dimX); + decRefs(mHal.state.mallocPtr, oldDimX - dimX, dimX); } - mPtr = realloc(mPtr, t->getSizeBytes()); + mHal.state.mallocPtr = realloc(mHal.state.mallocPtr, t->getSizeBytes()); if (dimX > oldDimX) { - const Element *e = mType->getElement(); + const Element *e = mHal.state.type->getElement(); uint32_t stride = e->getSizeBytes(); - memset(((uint8_t *)mPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX)); + memset(((uint8_t *)mHal.state.mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX)); } - mType.set(t); + + mHal.state.type.set(t); + updateCache(); } void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) { diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h index 4f5d5a8..e63140c 100644 --- a/libs/rs/rsAllocation.h +++ b/libs/rs/rsAllocation.h @@ -29,10 +29,35 @@ class Allocation : public ObjectBase { // The graphics equilivent of malloc. The allocation contains a structure of elements. public: + struct Hal { + void * drv; + + struct State { + ObjectBaseRef<const Type> type; + void * mallocPtr; + + uint32_t usageFlags; + RsAllocationMipmapControl mipmapControl; + + // Cached fields from the Type and Element + // to prevent pointer chasing in critical loops. + uint32_t dimensionX; + uint32_t dimensionY; + uint32_t dimensionZ; + uint32_t elementSizeBytes; + bool hasMipmaps; + bool hasFaces; + bool hasReferences; + }; + State state; + }; + Hal mHal; + Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE); virtual ~Allocation(); + void updateCache(); void setCpuWritable(bool); void setGpuWritable(bool); @@ -41,8 +66,8 @@ public: bool fixAllocation(); - void * getPtr() const {return mPtr;} - const Type * getType() const {return mType.get();} + void * getPtr() const {return mHal.state.mallocPtr;} + const Type * getType() const {return mHal.state.type.get();} void syncAll(Context *rsc, RsAllocationUsageType src); @@ -88,13 +113,13 @@ public: virtual void uploadCheck(Context *rsc); bool getIsScript() const { - return (mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT) != 0; + return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) != 0; } bool getIsTexture() const { - return (mUsageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) != 0; + return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) != 0; } bool getIsBufferObject() const { - return (mUsageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) != 0; + return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) != 0; } void incRefs(const void *ptr, size_t ct, size_t startOff = 0) const; @@ -102,14 +127,11 @@ public: void sendDirty() const; bool getHasGraphicsMipmaps() const { - return mMipmapControl != RS_ALLOCATION_MIPMAP_NONE; + return mHal.state.mipmapControl != RS_ALLOCATION_MIPMAP_NONE; } protected: - ObjectBaseRef<const Type> mType; - void * mPtr; - Vector<const Program *> mToDirtyList; // Is we have a non-null user bitmap callback we do not own the bits and @@ -123,9 +145,6 @@ protected: bool mGpuWrite; bool mGpuRead; - uint32_t mUsageFlags; - RsAllocationMipmapControl mMipmapControl; - // more usage hint data from the application // which can be used by a driver to pick the best memory type. // Likely ignored for now diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index c63d183..c761c75 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -429,6 +429,8 @@ void Context::displayDebugStats() { mStateFont.getFontColor(&oldR, &oldG, &oldB, &oldA); uint32_t bufferLen = strlen(buffer); + ObjectBaseRef<Font> lastFont(getFont()); + setFont(NULL); float shadowCol = 0.1f; mStateFont.setFontColor(shadowCol, shadowCol, shadowCol, 1.0f); mStateFont.renderText(buffer, bufferLen, 5, getHeight() - 6); @@ -436,6 +438,7 @@ void Context::displayDebugStats() { mStateFont.setFontColor(1.0f, 0.7f, 0.0f, 1.0f); mStateFont.renderText(buffer, bufferLen, 4, getHeight() - 7); + setFont(lastFont.get()); mStateFont.setFontColor(oldR, oldG, oldB, oldA); } @@ -551,56 +554,6 @@ void Context::destroyWorkerThreadResources() { mExit = true; } -void * Context::helperThreadProc(void *vrsc) { - Context *rsc = static_cast<Context *>(vrsc); - uint32_t idx = (uint32_t)android_atomic_inc(&rsc->mWorkers.mLaunchCount); - - //LOGV("RS helperThread starting %p idx=%i", rsc, idx); - - rsc->mWorkers.mLaunchSignals[idx].init(); - rsc->mWorkers.mNativeThreadId[idx] = gettid(); - -#if 0 - typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t; - cpu_set_t cpuset; - memset(&cpuset, 0, sizeof(cpuset)); - cpuset.bits[idx / 64] |= 1ULL << (idx % 64); - int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx], - sizeof(cpuset), &cpuset); - LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret)); -#endif - - setpriority(PRIO_PROCESS, rsc->mWorkers.mNativeThreadId[idx], rsc->mThreadPriority); - int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct); - if (status) { - LOGE("pthread_setspecific %i", status); - } - - while (!rsc->mExit) { - rsc->mWorkers.mLaunchSignals[idx].wait(); - if (rsc->mWorkers.mLaunchCallback) { - rsc->mWorkers.mLaunchCallback(rsc->mWorkers.mLaunchData, idx); - } - android_atomic_dec(&rsc->mWorkers.mRunningCount); - rsc->mWorkers.mCompleteSignal.set(); - } - - //LOGV("RS helperThread exited %p idx=%i", rsc, idx); - return NULL; -} - -void Context::launchThreads(WorkerCallback_t cbk, void *data) { - mWorkers.mLaunchData = data; - mWorkers.mLaunchCallback = cbk; - android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); - for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { - mWorkers.mLaunchSignals[ct].set(); - } - while (android_atomic_acquire_load(&mWorkers.mRunningCount) != 0) { - mWorkers.mCompleteSignal.wait(); - } -} - void Context::setPriority(int32_t p) { // Note: If we put this in the proper "background" policy // the wallpapers can become completly unresponsive at times. @@ -617,9 +570,6 @@ void Context::setPriority(int32_t p) { } #else setpriority(PRIO_PROCESS, mNativeThreadId, p); - for (uint32_t ct=0; ct < mWorkers.mCount; ct++) { - setpriority(PRIO_PROCESS, mWorkers.mNativeThreadId[ct], p); - } #endif } @@ -685,15 +635,12 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { timerInit(); timerSet(RS_TIMER_INTERNAL); - int cpu = sysconf(_SC_NPROCESSORS_ONLN); - LOGV("RS Launching thread(s), reported CPU count %i", cpu); - if (cpu < 2) cpu = 0; + if (!rsdHalInit(this, 0, 0)) { + LOGE("Hal init failed"); + return false; + } + mHal.funcs.setPriority(this, mThreadPriority); - mWorkers.mCount = (uint32_t)cpu; - mWorkers.mThreadId = (pthread_t *) calloc(mWorkers.mCount, sizeof(pthread_t)); - mWorkers.mNativeThreadId = (pid_t *) calloc(mWorkers.mCount, sizeof(pid_t)); - mWorkers.mLaunchSignals = new Signal[mWorkers.mCount]; - mWorkers.mLaunchCallback = NULL; status = pthread_create(&mThreadId, &threadAttr, threadProc, this); if (status) { LOGE("Failed to start rs context thread."); @@ -704,23 +651,10 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { } if (mError != RS_ERROR_NONE) { + LOGE("Errors during thread init"); return false; } - mWorkers.mCompleteSignal.init(); - android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); - android_atomic_release_store(0, &mWorkers.mLaunchCount); - for (uint32_t ct=0; ct < mWorkers.mCount; ct++) { - status = pthread_create(&mWorkers.mThreadId[ct], &threadAttr, helperThreadProc, this); - if (status) { - mWorkers.mCount = ct; - LOGE("Created fewer than expected number of RS threads."); - break; - } - } - while (android_atomic_acquire_load(&mWorkers.mRunningCount) != 0) { - usleep(100); - } pthread_attr_destroy(&threadAttr); return true; } @@ -737,17 +671,10 @@ Context::~Context() { mIO.shutdown(); int status = pthread_join(mThreadId, &res); - // Cleanup compute threads. - mWorkers.mLaunchData = NULL; - mWorkers.mLaunchCallback = NULL; - android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); - for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { - mWorkers.mLaunchSignals[ct].set(); - } - for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { - status = pthread_join(mWorkers.mThreadId[ct], &res); + + if (mHal.funcs.shutdownDriver) { + mHal.funcs.shutdownDriver(this); } - rsAssert(android_atomic_acquire_load(&mWorkers.mRunningCount) == 0); // Global structure cleanup. pthread_mutex_lock(&gInitMutex); diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index 50f63df..72574a6 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -22,6 +22,8 @@ #include "rsAllocation.h" #include "rsMesh.h" +#include "rs_hal.h" + #ifndef ANDROID_RS_SERIALIZE #include "rsMutex.h" #include "rsThreadIO.h" @@ -71,6 +73,13 @@ namespace renderscript { class Context { public: + struct Hal { + void * drv; + + RsdHalFunctions funcs; + }; + Hal mHal; + static Context * createContext(Device *, const RsSurfaceConfig *sc); ~Context(); @@ -81,11 +90,6 @@ public: // Library mutex (for providing thread-safe calls from the runtime) static pthread_mutex_t gLibMutex; - struct ScriptTLSStruct { - Context * mContext; - Script * mScript; - }; - class PushState { public: PushState(Context *); @@ -103,9 +107,6 @@ public: ScriptTLSStruct *mTlsStruct; RsSurfaceConfig mUserSurfaceConfig; - typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); - - //StructuredAllocationContext mStateAllocation; ElementState mStateElement; TypeState mStateType; SamplerState mStateSampler; @@ -216,8 +217,6 @@ public: uint32_t getMaxVertexUniformVectors() const {return mGL.mMaxVertexUniformVectors;} uint32_t getMaxVertexAttributes() const {return mGL.mMaxVertexAttribs;} - void launchThreads(WorkerCallback_t cbk, void *data); - uint32_t getWorkerPoolSize() const {return (uint32_t)mWorkers.mCount;} uint32_t getDPI() const {return mDPI;} void setDPI(uint32_t dpi) {mDPI = dpi;} @@ -274,20 +273,6 @@ protected: pthread_t mThreadId; pid_t mNativeThreadId; - struct Workers { - volatile int mRunningCount; - volatile int mLaunchCount; - uint32_t mCount; - pthread_t *mThreadId; - pid_t *mNativeThreadId; - Signal mCompleteSignal; - - Signal *mLaunchSignals; - WorkerCallback_t mLaunchCallback; - void *mLaunchData; - }; - Workers mWorkers; - ObjectBaseRef<Script> mRootScript; ObjectBaseRef<ProgramFragment> mFragment; ObjectBaseRef<ProgramVertex> mVertex; diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp index afee2a3..b84014f 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -21,6 +21,7 @@ using namespace android::renderscript; Script::Script(Context *rsc) : ObjectBase(rsc) { memset(&mEnviroment, 0, sizeof(mEnviroment)); + memset(&mHal, 0, sizeof(mHal)); mSlots = NULL; mTypes = NULL; @@ -37,48 +38,38 @@ Script::~Script() { } } -void Script::initSlots() { - if (mEnviroment.mFieldCount > 0) { - mSlots = new ObjectBaseRef<Allocation>[mEnviroment.mFieldCount]; - mTypes = new ObjectBaseRef<const Type>[mEnviroment.mFieldCount]; - } -} - void Script::setSlot(uint32_t slot, Allocation *a) { - if (slot >= mEnviroment.mFieldCount) { + //LOGE("setSlot %i %p", slot, a); + if (slot >= mHal.info.exportedVariableCount) { LOGE("Script::setSlot unable to set allocation, invalid slot index"); return; } mSlots[slot].set(a); + if (a != NULL) { + mRSC->mHal.funcs.script.setGlobalBind(mRSC, this, slot, a->getPtr()); + } else { + mRSC->mHal.funcs.script.setGlobalBind(mRSC, this, slot, NULL); + } } void Script::setVar(uint32_t slot, const void *val, uint32_t len) { - int32_t *destPtr = ((int32_t **)mEnviroment.mFieldAddress)[slot]; - if (destPtr) { - //LOGE("setVar f1 %f", ((const float *)destPtr)[0]); - //LOGE("setVar %p %i", destPtr, len); - memcpy(destPtr, val, len); - //LOGE("setVar f2 %f", ((const float *)destPtr)[0]); - } else { - //if (rsc->props.mLogScripts) { - LOGV("Calling setVar on slot = %i which is null", slot); - //} + //LOGE("setVar %i %p %i", slot, val, len); + if (slot >= mHal.info.exportedVariableCount) { + LOGE("Script::setVar unable to set allocation, invalid slot index"); + return; } + mRSC->mHal.funcs.script.setGlobalVar(mRSC, this, slot, (void *)val, len); } void Script::setVarObj(uint32_t slot, ObjectBase *val) { - ObjectBase **destPtr = ((ObjectBase ***)mEnviroment.mFieldAddress)[slot]; - - if (destPtr) { - if (val != NULL) { - val->incSysRef(); - } - if (*destPtr) { - (*destPtr)->decSysRef(); - } - *destPtr = val; + //LOGE("setVarObj %i %p", slot, val); + if (slot >= mHal.info.exportedVariableCount) { + LOGE("Script::setVarObj unable to set allocation, invalid slot index"); + return; } + //LOGE("setvarobj %i %p", slot, val); + mRSC->mHal.funcs.script.setGlobalObj(mRSC, this, slot, val); } namespace android { diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h index bad095b..671fbe6 100644 --- a/libs/rs/rsScript.h +++ b/libs/rs/rsScript.h @@ -31,6 +31,45 @@ class ProgramStore; class Script : public ObjectBase { public: + struct Hal { + void * drv; + + struct State { + ObjectBaseRef<const Type> type; + void * mallocPtr; + + uint32_t usageFlags; + RsAllocationMipmapControl mipmapControl; + + // Cached fields from the Type and Element + // to prevent pointer chasing in critical loops. + uint32_t dimensionX; + uint32_t dimensionY; + uint32_t dimensionZ; + uint32_t elementSizeBytes; + bool hasMipmaps; + bool hasFaces; + bool hasReferences; + }; + State state; + + struct DriverInfo { + int mVersionMajor; + int mVersionMinor; + + size_t exportedVariableCount; + size_t exportedFunctionCount; + size_t exportedPragmaCount; + char const **exportedPragmaKeyList; + char const **exportedPragmaValueList; + + int (* root)(); + bool isThreadable; + }; + DriverInfo info; + }; + Hal mHal; + typedef void (* InvokeFunc_t)(void); Script(Context *); @@ -45,16 +84,6 @@ public: ObjectBaseRef<ProgramFragment> mFragment; ObjectBaseRef<ProgramRaster> mRaster; ObjectBaseRef<ProgramStore> mFragmentStore; - - uint32_t mInvokeFunctionCount; - InvokeFunc_t *mInvokeFunctions; - uint32_t mFieldCount; - void ** mFieldAddress; - - char * mScriptText; - uint32_t mScriptTextLength; - - bool mIsThreadable; }; Enviroment_t mEnviroment; diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index e12926b..d5c486b 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -19,9 +19,6 @@ #include "rsMatrix.h" #include "utils/Timers.h" #include "utils/StopWatch.h" -extern "C" { -#include "libdex/ZipArchive.h" -} #include <GLES/gl.h> #include <GLES/glext.h> @@ -36,94 +33,18 @@ using namespace android::renderscript; Context * rsc = tls->mContext; \ ScriptC * sc = (ScriptC *) tls->mScript -// Input: cacheDir -// Input: resName -// Input: extName -// -// Note: cacheFile = resName + extName -// -// Output: Returns cachePath == cacheDir + cacheFile -char *genCacheFileName(const char *cacheDir, - const char *resName, - const char *extName) { - char cachePath[512]; - char cacheFile[sizeof(cachePath)]; - const size_t kBufLen = sizeof(cachePath) - 1; - - cacheFile[0] = '\0'; - // Note: resName today is usually something like - // "/com.android.fountain:raw/fountain" - if (resName[0] != '/') { - // Get the absolute path of the raw/***.bc file. - - // Generate the absolute path. This doesn't do everything it - // should, e.g. if resName is "./out/whatever" it doesn't crunch - // the leading "./" out because this if-block is not triggered, - // but it'll make do. - // - if (getcwd(cacheFile, kBufLen) == NULL) { - LOGE("Can't get CWD while opening raw/***.bc file\n"); - return NULL; - } - // Append "/" at the end of cacheFile so far. - strncat(cacheFile, "/", kBufLen); - } - - // cacheFile = resName + extName - // - strncat(cacheFile, resName, kBufLen); - if (extName != NULL) { - // TODO(srhines): strncat() is a bit dangerous - strncat(cacheFile, extName, kBufLen); - } - - // Turn the path into a flat filename by replacing - // any slashes after the first one with '@' characters. - char *cp = cacheFile + 1; - while (*cp != '\0') { - if (*cp == '/') { - *cp = '@'; - } - cp++; - } - - // Tack on the file name for the actual cache file path. - strncpy(cachePath, cacheDir, kBufLen); - strncat(cachePath, cacheFile, kBufLen); - - LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath); - return strdup(cachePath); -} - ScriptC::ScriptC(Context *rsc) : Script(rsc) { - mBccScript = NULL; - memset(&mProgram, 0, sizeof(mProgram)); } ScriptC::~ScriptC() { - if (mBccScript) { - if (mProgram.mObjectSlotList) { - for (size_t ct=0; ct < mProgram.mObjectSlotCount; ct++) { - setVarObj(mProgram.mObjectSlotList[ct], NULL); - } - delete [] mProgram.mObjectSlotList; - mProgram.mObjectSlotList = NULL; - mProgram.mObjectSlotCount = 0; - } - - - LOGD(">>>> ~ScriptC bccDisposeScript(%p)", mBccScript); - bccDisposeScript(mBccScript); - } - free(mEnviroment.mScriptText); - mEnviroment.mScriptText = NULL; + mRSC->mHal.funcs.script.destroy(mRSC, this); } void ScriptC::setupScript(Context *rsc) { mEnviroment.mStartTimeMillis = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); - for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) { + for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) { if (mSlots[ct].get() && !mTypes[ct].get()) { mTypes[ct].set(mSlots[ct]->getType()); } @@ -134,27 +55,17 @@ void ScriptC::setupScript(Context *rsc) { if (mSlots[ct].get()) { ptr = mSlots[ct]->getPtr(); } - void **dest = ((void ***)mEnviroment.mFieldAddress)[ct]; - if (rsc->props.mLogScripts) { - if (mSlots[ct].get() != NULL) { - LOGV("%p ScriptC::setupScript slot=%i dst=%p src=%p type=%p", rsc, ct, dest, ptr, mSlots[ct]->getType()); - } else { - LOGV("%p ScriptC::setupScript slot=%i dst=%p src=%p type=null", rsc, ct, dest, ptr); - } - } - - if (dest) { - *dest = ptr; - } + rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, ptr); } } const Allocation *ScriptC::ptrToAllocation(const void *ptr) const { + //LOGE("ptr to alloc %p", ptr); if (!ptr) { return NULL; } - for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) { + for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) { if (!mSlots[ct].get()) continue; if (mSlots[ct]->getPtr() == ptr) { @@ -165,15 +76,6 @@ const Allocation *ScriptC::ptrToAllocation(const void *ptr) const { return NULL; } -Script * ScriptC::setTLS(Script *sc) { - Context::ScriptTLSStruct * tls = (Context::ScriptTLSStruct *) - pthread_getspecific(Context::gThreadTLSKey); - rsAssert(tls); - Script *old = tls->mScript; - tls->mScript = sc; - return old; -} - void ScriptC::setupGLState(Context *rsc) { if (mEnviroment.mFragmentStore.get()) { rsc->setProgramStore(mEnviroment.mFragmentStore.get()); @@ -190,7 +92,7 @@ void ScriptC::setupGLState(Context *rsc) { } uint32_t ScriptC::run(Context *rsc) { - if (mProgram.mRoot == NULL) { + if (mHal.info.root == NULL) { rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script"); return 0; } @@ -199,235 +101,45 @@ uint32_t ScriptC::run(Context *rsc) { setupScript(rsc); uint32_t ret = 0; - Script * oldTLS = setTLS(this); if (rsc->props.mLogScripts) { - LOGV("%p ScriptC::run invoking root, ptr %p", rsc, mProgram.mRoot); + LOGV("%p ScriptC::run invoking root, ptr %p", rsc, mHal.info.root); } - ret = mProgram.mRoot(); + ret = rsc->mHal.funcs.script.invokeRoot(rsc, this); if (rsc->props.mLogScripts) { LOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret); } - setTLS(oldTLS); return ret; } -typedef struct { - Context *rsc; - ScriptC *script; - const Allocation * ain; - Allocation * aout; - const void * usr; - - uint32_t mSliceSize; - volatile int mSliceNum; - - const uint8_t *ptrIn; - uint32_t eStrideIn; - uint8_t *ptrOut; - uint32_t eStrideOut; - - uint32_t xStart; - uint32_t xEnd; - uint32_t yStart; - uint32_t yEnd; - uint32_t zStart; - uint32_t zEnd; - uint32_t arrayStart; - uint32_t arrayEnd; - - uint32_t dimX; - uint32_t dimY; - uint32_t dimZ; - uint32_t dimArray; -} MTLaunchStruct; -typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); - -static void wc_xy(void *usr, uint32_t idx) { - MTLaunchStruct *mtls = (MTLaunchStruct *)usr; - - while (1) { - uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); - uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize; - uint32_t yEnd = yStart + mtls->mSliceSize; - yEnd = rsMin(yEnd, mtls->yEnd); - if (yEnd <= yStart) { - return; - } - - //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); - //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); - for (uint32_t y = yStart; y < yEnd; y++) { - uint32_t offset = mtls->dimX * y; - uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset); - const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset); - - for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) { - ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0); - xPtrIn += mtls->eStrideIn; - xPtrOut += mtls->eStrideOut; - } - } - } -} - -static void wc_x(void *usr, uint32_t idx) { - MTLaunchStruct *mtls = (MTLaunchStruct *)usr; - - while (1) { - uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); - uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize; - uint32_t xEnd = xStart + mtls->mSliceSize; - xEnd = rsMin(xEnd, mtls->xEnd); - if (xEnd <= xStart) { - return; - } - - //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); - //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); - uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart); - const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart); - for (uint32_t x = xStart; x < xEnd; x++) { - ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0); - xPtrIn += mtls->eStrideIn; - xPtrOut += mtls->eStrideOut; - } - } -} void ScriptC::runForEach(Context *rsc, const Allocation * ain, Allocation * aout, const void * usr, const RsScriptCall *sc) { - MTLaunchStruct mtls; - memset(&mtls, 0, sizeof(mtls)); - Context::PushState ps(rsc); - - if (ain) { - mtls.dimX = ain->getType()->getDimX(); - mtls.dimY = ain->getType()->getDimY(); - mtls.dimZ = ain->getType()->getDimZ(); - //mtls.dimArray = ain->getType()->getDimArray(); - } else if (aout) { - mtls.dimX = aout->getType()->getDimX(); - mtls.dimY = aout->getType()->getDimY(); - mtls.dimZ = aout->getType()->getDimZ(); - //mtls.dimArray = aout->getType()->getDimArray(); - } else { - rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations"); - return; - } - - if (!sc || (sc->xEnd == 0)) { - mtls.xEnd = mtls.dimX; - } else { - rsAssert(sc->xStart < mtls.dimX); - rsAssert(sc->xEnd <= mtls.dimX); - rsAssert(sc->xStart < sc->xEnd); - mtls.xStart = rsMin(mtls.dimX, sc->xStart); - mtls.xEnd = rsMin(mtls.dimX, sc->xEnd); - if (mtls.xStart >= mtls.xEnd) return; - } - - if (!sc || (sc->yEnd == 0)) { - mtls.yEnd = mtls.dimY; - } else { - rsAssert(sc->yStart < mtls.dimY); - rsAssert(sc->yEnd <= mtls.dimY); - rsAssert(sc->yStart < sc->yEnd); - mtls.yStart = rsMin(mtls.dimY, sc->yStart); - mtls.yEnd = rsMin(mtls.dimY, sc->yEnd); - if (mtls.yStart >= mtls.yEnd) return; - } - - mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd); - mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd); - mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd); - mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd); - rsAssert(ain->getType()->getDimZ() == 0); + Context::PushState ps(rsc); setupGLState(rsc); setupScript(rsc); - Script * oldTLS = setTLS(this); - - mtls.rsc = rsc; - mtls.ain = ain; - mtls.aout = aout; - mtls.script = this; - mtls.usr = usr; - mtls.mSliceSize = 10; - mtls.mSliceNum = 0; - - mtls.ptrIn = NULL; - mtls.eStrideIn = 0; - if (ain) { - mtls.ptrIn = (const uint8_t *)ain->getPtr(); - mtls.eStrideIn = ain->getType()->getElementSizeBytes(); - } - - mtls.ptrOut = NULL; - mtls.eStrideOut = 0; - if (aout) { - mtls.ptrOut = (uint8_t *)aout->getPtr(); - mtls.eStrideOut = aout->getType()->getElementSizeBytes(); - } - - if ((rsc->getWorkerPoolSize() > 1) && mEnviroment.mIsThreadable) { - if (mtls.dimY > 1) { - rsc->launchThreads(wc_xy, &mtls); - } else { - rsc->launchThreads(wc_x, &mtls); - } - - //LOGE("launch 1"); - } else { - //LOGE("launch 3"); - for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) { - for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) { - for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) { - uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar + - mtls.dimX * mtls.dimY * z + - mtls.dimX * y; - uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset); - const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset); - - for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) { - ((rs_t)mProgram.mRoot) (xPtrIn, xPtrOut, usr, x, y, z, ar); - xPtrIn += mtls.eStrideIn; - xPtrOut += mtls.eStrideOut; - } - } - } - } - } - - setTLS(oldTLS); + rsc->mHal.funcs.script.invokeForEach(rsc, this, ain, aout, usr, 0, sc); } void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) { - if ((slot >= mEnviroment.mInvokeFunctionCount) || - (mEnviroment.mInvokeFunctions[slot] == NULL)) { + if (slot >= mHal.info.exportedFunctionCount) { rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script"); return; } setupScript(rsc); - Script * oldTLS = setTLS(this); if (rsc->props.mLogScripts) { - LOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, mEnviroment.mInvokeFunctions[slot]); - } - ((void (*)(const void *, uint32_t)) - mEnviroment.mInvokeFunctions[slot])(data, len); - if (rsc->props.mLogScripts) { - LOGV("%p ScriptC::Invoke complete", rsc); + LOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, this); } - - setTLS(oldTLS); + rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len); } ScriptCState::ScriptCState() { @@ -440,9 +152,9 @@ static void* symbolLookup(void* pContext, char const* name) { const ScriptCState::SymbolTable_t *sym; ScriptC *s = (ScriptC *)pContext; if (!strcmp(name, "__isThreadable")) { - return (void*) s->mEnviroment.mIsThreadable; + return (void*) s->mHal.info.isThreadable; } else if (!strcmp(name, "__clearThreadable")) { - s->mEnviroment.mIsThreadable = false; + s->mHal.info.isThreadable = false; return NULL; } sym = ScriptCState::lookupSymbol(name); @@ -453,7 +165,7 @@ static void* symbolLookup(void* pContext, char const* name) { sym = ScriptCState::lookupSymbolGL(name); } if (sym) { - s->mEnviroment.mIsThreadable &= sym->threadable; + s->mHal.info.isThreadable &= sym->threadable; return sym->mPtr; } LOGE("ScriptC sym lookup failed for %s", name); @@ -465,144 +177,86 @@ extern const char rs_runtime_lib_bc[]; extern unsigned rs_runtime_lib_bc_size; #endif -bool ScriptCState::runCompiler(Context *rsc, - ScriptC *s, - const char *resName, - const char *cacheDir) { - s->mBccScript = bccCreateScript(); +bool ScriptC::runCompiler(Context *rsc, + const char *resName, + const char *cacheDir, + const uint8_t *bitcode, + size_t bitcodeLen) { - s->mEnviroment.mIsThreadable = true; + //LOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen); - if (bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s) != 0) { - LOGE("bcc: FAILS to register symbol callback"); - return false; - } + rsc->mHal.funcs.script.scriptInit(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0, symbolLookup); - if (bccReadBC(s->mBccScript, - resName, - s->mEnviroment.mScriptText, - s->mEnviroment.mScriptTextLength, 0) != 0) { - LOGE("bcc: FAILS to read bitcode"); - return false; - } + mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); + mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); + mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); + mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); -#if 1 - if (bccLinkFile(s->mBccScript, "/system/lib/libclcore.bc", 0) != 0) { - LOGE("bcc: FAILS to link bitcode"); - return false; - } -#endif - char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC"); - - if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) { - LOGE("bcc: FAILS to prepare executable"); - return false; - } + rsc->mHal.funcs.script.invokeInit(rsc, this); - free(cachePath); - - s->mProgram.mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(s->mBccScript, "root")); - s->mProgram.mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(s->mBccScript, "init")); - - if (s->mProgram.mInit) { - s->mProgram.mInit(); - } - - s->mEnviroment.mInvokeFunctionCount = bccGetExportFuncCount(s->mBccScript); - if (s->mEnviroment.mInvokeFunctionCount <= 0) - s->mEnviroment.mInvokeFunctions = NULL; - else { - s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t*) calloc(s->mEnviroment.mInvokeFunctionCount, sizeof(Script::InvokeFunc_t)); - bccGetExportFuncList(s->mBccScript, s->mEnviroment.mInvokeFunctionCount, (void **) s->mEnviroment.mInvokeFunctions); - } - - s->mEnviroment.mFieldCount = bccGetExportVarCount(s->mBccScript); - if (s->mEnviroment.mFieldCount <= 0) - s->mEnviroment.mFieldAddress = NULL; - else { - s->mEnviroment.mFieldAddress = (void **) calloc(s->mEnviroment.mFieldCount, sizeof(void *)); - bccGetExportVarList(s->mBccScript, s->mEnviroment.mFieldCount, (void **) s->mEnviroment.mFieldAddress); - s->initSlots(); - } - - s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); - s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); - s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); - s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); - - const static int pragmaMax = 16; - size_t pragmaCount = bccGetPragmaCount(s->mBccScript); - char const *keys[pragmaMax]; - char const *values[pragmaMax]; - bccGetPragmaList(s->mBccScript, pragmaMax, keys, values); - - for (size_t i=0; i < pragmaCount; ++i) { + for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) { + const char * key = mHal.info.exportedPragmaKeyList[i]; + const char * value = mHal.info.exportedPragmaValueList[i]; //LOGE("pragma %s %s", keys[i], values[i]); - if (!strcmp(keys[i], "version")) { - if (!strcmp(values[i], "1")) { + if (!strcmp(key, "version")) { + if (!strcmp(value, "1")) { continue; } - LOGE("Invalid version pragma value: %s\n", values[i]); + LOGE("Invalid version pragma value: %s\n", value); return false; } - if (!strcmp(keys[i], "stateVertex")) { - if (!strcmp(values[i], "default")) { + if (!strcmp(key, "stateVertex")) { + if (!strcmp(value, "default")) { continue; } - if (!strcmp(values[i], "parent")) { - s->mEnviroment.mVertex.clear(); + if (!strcmp(value, "parent")) { + mEnviroment.mVertex.clear(); continue; } - LOGE("Unrecognized value %s passed to stateVertex", values[i]); + LOGE("Unrecognized value %s passed to stateVertex", value); return false; } - if (!strcmp(keys[i], "stateRaster")) { - if (!strcmp(values[i], "default")) { + if (!strcmp(key, "stateRaster")) { + if (!strcmp(value, "default")) { continue; } - if (!strcmp(values[i], "parent")) { - s->mEnviroment.mRaster.clear(); + if (!strcmp(value, "parent")) { + mEnviroment.mRaster.clear(); continue; } - LOGE("Unrecognized value %s passed to stateRaster", values[i]); + LOGE("Unrecognized value %s passed to stateRaster", value); return false; } - if (!strcmp(keys[i], "stateFragment")) { - if (!strcmp(values[i], "default")) { + if (!strcmp(key, "stateFragment")) { + if (!strcmp(value, "default")) { continue; } - if (!strcmp(values[i], "parent")) { - s->mEnviroment.mFragment.clear(); + if (!strcmp(value, "parent")) { + mEnviroment.mFragment.clear(); continue; } - LOGE("Unrecognized value %s passed to stateFragment", values[i]); + LOGE("Unrecognized value %s passed to stateFragment", value); return false; } - if (!strcmp(keys[i], "stateStore")) { - if (!strcmp(values[i], "default")) { + if (!strcmp(key, "stateStore")) { + if (!strcmp(value, "default")) { continue; } - if (!strcmp(values[i], "parent")) { - s->mEnviroment.mFragmentStore.clear(); + if (!strcmp(value, "parent")) { + mEnviroment.mFragmentStore.clear(); continue; } - LOGE("Unrecognized value %s passed to stateStore", values[i]); + LOGE("Unrecognized value %s passed to stateStore", value); return false; } } - size_t objectSlotCount = bccGetObjectSlotCount(s->mBccScript); - uint32_t *objectSlots = NULL; - if (objectSlotCount) { - objectSlots = new uint32_t[objectSlotCount]; - bccGetObjectSlotList(s->mBccScript, objectSlotCount, objectSlots); - s->mProgram.mObjectSlotList = objectSlots; - s->mProgram.mObjectSlotCount = objectSlotCount; - } + mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount]; + mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount]; return true; } @@ -610,39 +264,19 @@ bool ScriptCState::runCompiler(Context *rsc, namespace android { namespace renderscript { -void rsi_ScriptCBegin(Context * rsc) { -} - -void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) { - ScriptCState *ss = &rsc->mScriptC; - - char *t = (char *)malloc(len + 1); - memcpy(t, text, len); - t[len] = 0; - ss->mScriptText = t; - ss->mScriptLen = len; -} - - RsScript rsi_ScriptCCreate(Context *rsc, - const char *packageName /* deprecated */, - const char *resName, - const char *cacheDir) + const char *resName, const char *cacheDir, + const char *text, uint32_t len) { - ScriptCState *ss = &rsc->mScriptC; - ScriptC *s = new ScriptC(rsc); - s->mEnviroment.mScriptText = ss->mScriptText; - s->mEnviroment.mScriptTextLength = ss->mScriptLen; - ss->mScriptText = NULL; - ss->mScriptLen = 0; - s->incUserRef(); - if (!ss->runCompiler(rsc, s, resName, cacheDir)) { + if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, len)) { // Error during compile, destroy s and return null. delete s; return NULL; } + + s->incUserRef(); return s; } diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h index 2c74b5b..2edeb9b 100644 --- a/libs/rs/rsScriptC.h +++ b/libs/rs/rsScriptC.h @@ -21,7 +21,6 @@ #include "RenderScriptEnv.h" -struct BCCOpaqueScript; // --------------------------------------------------------------------------- namespace android { @@ -36,21 +35,6 @@ public: ScriptC(Context *); virtual ~ScriptC(); - struct Program_t { - int mVersionMajor; - int mVersionMinor; - - RunScript_t mRoot; - VoidFunc_t mInit; - - uint32_t * mObjectSlotList; - uint32_t mObjectSlotCount; - }; - - - Program_t mProgram; - - BCCOpaqueScript *mBccScript; const Allocation *ptrToAllocation(const void *) const; @@ -69,7 +53,10 @@ public: virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SCRIPT_C; } static Type *createFromStream(Context *rsc, IStream *stream) { return NULL; } -protected: + bool runCompiler(Context *rsc, const char *resName, const char *cacheDir, + const uint8_t *bitcode, size_t bitcodeLen); + +//protected: void setupScript(Context *); void setupGLState(Context *); Script * setTLS(Script *); @@ -83,8 +70,6 @@ public: char * mScriptText; size_t mScriptLen; - bool runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir); - struct SymbolTable_t { const char * mName; void * mPtr; diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp index 23230a6..4e8cbdc 100644 --- a/libs/rs/rsScriptC_Lib.cpp +++ b/libs/rs/rsScriptC_Lib.cpp @@ -25,8 +25,8 @@ using namespace android; using namespace android::renderscript; -#define GET_TLS() Context::ScriptTLSStruct * tls = \ - (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ +#define GET_TLS() ScriptTLSStruct * tls = \ + (ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ Context * rsc = tls->mContext; \ ScriptC * sc = (ScriptC *) tls->mScript @@ -141,90 +141,74 @@ static float SC_getDt() { // ////////////////////////////////////////////////////////////////////////////// -static uint32_t SC_allocGetDimX(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); +static uint32_t SC_allocGetDimX(Allocation *a) { CHECK_OBJ(a); - //LOGE("SC_allocGetDimX a=%p type=%p", a, a->getType()); - return a->getType()->getDimX(); + return a->mHal.state.dimensionX; } -static uint32_t SC_allocGetDimY(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); +static uint32_t SC_allocGetDimY(Allocation *a) { CHECK_OBJ(a); - return a->getType()->getDimY(); + return a->mHal.state.dimensionY; } -static uint32_t SC_allocGetDimZ(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); +static uint32_t SC_allocGetDimZ(Allocation *a) { CHECK_OBJ(a); - return a->getType()->getDimZ(); + return a->mHal.state.dimensionZ; } -static uint32_t SC_allocGetDimLOD(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); +static uint32_t SC_allocGetDimLOD(Allocation *a) { CHECK_OBJ(a); - return a->getType()->getDimLOD(); + return a->mHal.state.hasMipmaps; } -static uint32_t SC_allocGetDimFaces(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); +static uint32_t SC_allocGetDimFaces(Allocation *a) { CHECK_OBJ(a); - return a->getType()->getDimFaces(); + return a->mHal.state.hasFaces; } -static const void * SC_getElementAtX(RsAllocation va, uint32_t x) { - const Allocation *a = static_cast<const Allocation *>(va); +static const void * SC_getElementAtX(Allocation *a, uint32_t x) { CHECK_OBJ(a); - const Type *t = a->getType(); - CHECK_OBJ(t); const uint8_t *p = (const uint8_t *)a->getPtr(); - return &p[t->getElementSizeBytes() * x]; + return &p[a->mHal.state.elementSizeBytes * x]; } -static const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y) { - const Allocation *a = static_cast<const Allocation *>(va); +static const void * SC_getElementAtXY(Allocation *a, uint32_t x, uint32_t y) { CHECK_OBJ(a); - const Type *t = a->getType(); - CHECK_OBJ(t); const uint8_t *p = (const uint8_t *)a->getPtr(); - return &p[t->getElementSizeBytes() * (x + y*t->getDimX())]; + return &p[a->mHal.state.elementSizeBytes * (x + y * a->mHal.state.dimensionX)]; } -static const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z) { - const Allocation *a = static_cast<const Allocation *>(va); +static const void * SC_getElementAtXYZ(Allocation *a, uint32_t x, uint32_t y, uint32_t z) { CHECK_OBJ(a); - const Type *t = a->getType(); - CHECK_OBJ(t); const uint8_t *p = (const uint8_t *)a->getPtr(); - return &p[t->getElementSizeBytes() * (x + y*t->getDimX())]; + return &p[a->mHal.state.elementSizeBytes * (x + y * a->mHal.state.dimensionX + + z * a->mHal.state.dimensionX * a->mHal.state.dimensionY)]; } -static void SC_setObject(void **vdst, void * vsrc) { - //LOGE("SC_setObject %p,%p %p", vdst, *vdst, vsrc); - if (vsrc) { - CHECK_OBJ(vsrc); - static_cast<ObjectBase *>(vsrc)->incSysRef(); +void android::renderscript::rsiSetObject(ObjectBase **dst, ObjectBase * src) { + //LOGE("rsiSetObject %p,%p %p", vdst, *vdst, vsrc); + if (src) { + CHECK_OBJ(src); + src->incSysRef(); } - if (vdst[0]) { - CHECK_OBJ(vdst[0]); - static_cast<ObjectBase *>(vdst[0])->decSysRef(); + if (dst[0]) { + CHECK_OBJ(dst[0]); + dst[0]->decSysRef(); } - *vdst = vsrc; - //LOGE("SC_setObject *"); + *dst = src; } -static void SC_clearObject(void **vdst) { - //LOGE("SC_clearObject %p,%p", vdst, *vdst); - if (vdst[0]) { - CHECK_OBJ(vdst[0]); - static_cast<ObjectBase *>(vdst[0])->decSysRef(); +void android::renderscript::rsiClearObject(ObjectBase **dst) { + //LOGE("rsiClearObject %p,%p", vdst, *vdst); + if (dst[0]) { + CHECK_OBJ(dst[0]); + dst[0]->decSysRef(); } - *vdst = NULL; - //LOGE("SC_clearObject *"); + *dst = NULL; } -static bool SC_isObject(RsAllocation vsrc) { - return vsrc != NULL; +bool android::renderscript::rsiIsObject(const ObjectBase *src) { + return src != NULL; } static void SC_debugF(const char *s, float f) { @@ -873,49 +857,49 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true }, { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true }, - { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject10rs_element", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP10rs_elementS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP10rs_element", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject10rs_element", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject7rs_type", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP7rs_typeS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP7rs_type", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject7rs_type", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP13rs_allocationS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP13rs_allocation", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject13rs_allocation", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP10rs_samplerS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP10rs_sampler", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject10rs_sampler", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject9rs_script", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP9rs_scriptS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP9rs_script", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject9rs_script", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP7rs_meshS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP7rs_mesh", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject7rs_mesh", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP19rs_program_fragment", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject19rs_program_fragment", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP17rs_program_vertex", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject17rs_program_vertex", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP17rs_program_raster", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject17rs_program_raster", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP16rs_program_store", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject16rs_program_store", (void *)&rsiIsObject, true }, - { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject7rs_font", (void *)&SC_isObject, true }, + { "_Z11rsSetObjectP7rs_fontS_", (void *)&rsiSetObject, true }, + { "_Z13rsClearObjectP7rs_font", (void *)&rsiClearObject, true }, + { "_Z10rsIsObject7rs_font", (void *)&rsiIsObject, true }, { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty, true }, @@ -1000,7 +984,7 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_2x2, true }, { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false }, - //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, true }, + //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, false }, //////////////////////////////////////////////////////////////////// @@ -1021,3 +1005,4 @@ const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym) } return NULL; } + diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp index 15426bc..4047049 100644 --- a/libs/rs/rsScriptC_LibGL.cpp +++ b/libs/rs/rsScriptC_LibGL.cpp @@ -32,8 +32,8 @@ using namespace android; using namespace android::renderscript; -#define GET_TLS() Context::ScriptTLSStruct * tls = \ - (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ +#define GET_TLS() ScriptTLSStruct * tls = \ + (ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ Context * rsc = tls->mContext; \ ScriptC * sc = (ScriptC *) tls->mScript diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h new file mode 100644 index 0000000..17983ce --- /dev/null +++ b/libs/rs/rs_hal.h @@ -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. + */ + +#ifndef RS_HAL_H +#define RS_HAL_H + +#include <RenderScriptDefines.h> + +namespace android { +namespace renderscript { + +class Context; +class ObjectBase; +class Element; +class Type; +class Allocation; +class Script; +class ScriptC; + + +typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName); + +typedef struct ScriptTLSStructRec { + Context * mContext; + Script * mScript; +} ScriptTLSStruct; + + +/** + * Script management functions + */ +typedef struct { + void (*shutdownDriver)(Context *); + void (*getVersion)(unsigned int *major, unsigned int *minor); + void (*setPriority)(const Context *, int32_t priority); + + + + struct { + bool (*scriptInit)(const Context *rsc, ScriptC *s, + char const *resName, + char const *cacheDir, + uint8_t const *bitcode, + size_t bitcodeSize, + uint32_t flags, + RsHalSymbolLookupFunc lookupFunc); + + void (*invokeFunction)(const Context *rsc, Script *s, + uint32_t slot, + const void *params, + size_t paramLength); + int (*invokeRoot)(const Context *rsc, Script *s); + void (*invokeForEach)(const Context *rsc, + Script *s, + const Allocation * ain, + Allocation * aout, + const void * usr, + uint32_t usrLen, + const RsScriptCall *sc); + void (*invokeInit)(const Context *rsc, Script *s); + + void (*setGlobalVar)(const Context *rsc, const Script *s, + uint32_t slot, + void *data, + size_t dataLength); + void (*setGlobalBind)(const Context *rsc, const Script *s, + uint32_t slot, + void *data); + void (*setGlobalObj)(const Context *rsc, const Script *s, + uint32_t slot, + ObjectBase *data); + + void (*destroy)(const Context *rsc, Script *s); + } script; + + + +} RsdHalFunctions; + +void rsiSetObject(ObjectBase **vdst, ObjectBase * vsrc); +void rsiClearObject(ObjectBase **vdst); +bool rsiIsObject(const ObjectBase *vdst); + +} +} + + +bool rsdHalInit(android::renderscript::Context *, uint32_t version_major, uint32_t version_minor); + +#endif + diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk index 4a0faf0..267e3edf 100644 --- a/libs/surfaceflinger_client/Android.mk +++ b/libs/surfaceflinger_client/Android.mk @@ -1,22 +1,9 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ - ISurfaceComposer.cpp \ - ISurface.cpp \ - ISurfaceComposerClient.cpp \ - IGraphicBufferAlloc.cpp \ - LayerState.cpp \ - SharedBufferStack.cpp \ - Surface.cpp \ - SurfaceComposerClient.cpp +LOCAL_SRC_FILES:= -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libbinder \ - libhardware \ - libui +LOCAL_SHARED_LIBRARIES := LOCAL_MODULE:= libsurfaceflinger_client diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk deleted file mode 100644 index 212b8e7..0000000 --- a/libs/surfaceflinger_client/tests/Android.mk +++ /dev/null @@ -1,53 +0,0 @@ -# Build the unit tests. -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -ifneq ($(TARGET_SIMULATOR),true) - -# Build the unit tests. -test_src_files := \ - Surface_test.cpp \ - -shared_libraries := \ - libcutils \ - libutils \ - libbinder \ - libsurfaceflinger_client \ - libstlport \ - -static_libraries := \ - libgtest \ - libgtest_main \ - -c_includes := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ - -module_tags := tests - -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_C_INCLUDES := $(c_includes)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ - $(eval include $(BUILD_EXECUTABLE)) \ -) - -# Build the manual test programs. -include $(call all-subdir-makefiles) - -endif - -# Include subdirectory makefiles -# ============================================================ - -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk deleted file mode 100644 index d3dfe04..0000000 --- a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - SharedBufferStackTest.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libui \ - libsurfaceflinger_client - -LOCAL_MODULE:= test-sharedbufferstack - -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp deleted file mode 100644 index 7ef5926..0000000 --- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (C) 2007 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 NDEBUG - -#include <assert.h> -#include <cutils/memory.h> -#include <cutils/log.h> -#include <utils/Errors.h> -#include <private/surfaceflinger/SharedBufferStack.h> - -using namespace android; - -void log(const char* prefix, int *b, size_t num); -void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); - -// ---------------------------------------------------------------------------- - -int main(int argc, char** argv) -{ - SharedClient client; - sp<SharedBufferServer> ps(new SharedBufferServer(&client, 0, 4, 0)); - SharedBufferServer& s(*ps); - SharedBufferClient c(&client, 0, 4, 0); - - printf("basic test 0\n"); - int list0[4] = {0, 1, 2, 3}; - test0(s, c, 4, list0); - - printf("basic test 1\n"); - int list1[4] = {2, 1, 0, 3}; - test0(s, c, 4, list1); - - int b = c.dequeue(); - c.lock(b); - c.queue(b); - s.retireAndLock(); - - printf("basic test 2\n"); - int list2[4] = {1, 2, 3, 0}; - test0(s, c, 4, list2); - - - printf("resize test\n"); - class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { - SharedBufferServer& s; - virtual status_t operator()(int bufferCount) const { - return s.resize(bufferCount); - } - public: - SetBufferCountIPC(SharedBufferServer& s) : s(s) { } - } resize(s); - - c.setBufferCount(6, resize); - int list3[6] = {3, 2, 1, 4, 5, 0}; - test0(s, c, 6, list3); - - c.setBufferCount(4, resize); - int list4[4] = {1, 2, 3, 0}; - test0(s, c, 4, list4); - - return 0; -} - -void log(const char* prefix, int *b, size_t num) -{ - printf("%s: ", prefix); - for (size_t i=0 ; i<num ; i++) { - printf("%d ", b[i]); - } - printf("\n"); -} - -// ---------------------------------------------------------------------------- - -void test0( - SharedBufferServer& s, - SharedBufferClient& c, - size_t num, - int* list) -{ - status_t err; - int b[num], u[num], r[num]; - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==list[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==list[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(b[num-1]); - assert(err == 0); - log("LK", b+num-1, 1); - - err = c.queue(b[num-1]); - assert(err == 0); - log(" Q", b+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==list[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==list[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - u[i] = b[num-2-i]; - } - u[num-1] = b[num-1]; - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(u[i]); - assert(err==0); - } - log(" Q", u, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(b[num-1]); - assert(err == 0); - log("LK", b+num-1, 1); - - err = c.queue(b[num-1]); - assert(err == 0); - log(" Q", b+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==list[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==u[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(u[num-1]); - assert(err == 0); - log("LK", u+num-1, 1); - - err = c.queue(u[num-1]); - assert(err == 0); - log(" Q", u+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==u[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - b[0] = c.dequeue(); - assert(b[0]==u[0]); - log("DQ", b, 1); - - c.undoDequeue(b[0]); - assert(err == 0); - log("UDQ", b, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==u[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(u[num-1]); - assert(err == 0); - log("LK", u+num-1, 1); - - err = c.queue(u[num-1]); - assert(err == 0); - log(" Q", u+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==u[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - printf("\n"); -} diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index e2e698e..440ec00 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -7,8 +7,12 @@ //#define LOG_NDEBUG 0 +// Log debug messages about keymap probing. #define DEBUG_PROBE 0 +// Log debug messages about velocity tracking. +#define DEBUG_VELOCITY 0 + #include <stdlib.h> #include <unistd.h> #include <ctype.h> @@ -329,6 +333,27 @@ void PointerCoords::tooManyAxes(int axis) { "cannot contain more than %d axis values.", axis, int(MAX_AXES)); } +bool PointerCoords::operator==(const PointerCoords& other) const { + if (bits != other.bits) { + return false; + } + uint32_t count = __builtin_popcountll(bits); + for (uint32_t i = 0; i < count; i++) { + if (values[i] != other.values[i]) { + return false; + } + } + return true; +} + +void PointerCoords::copyFrom(const PointerCoords& other) { + bits = other.bits; + uint32_t count = __builtin_popcountll(bits); + for (uint32_t i = 0; i < count; i++) { + values[i] = other.values[i]; + } +} + // --- MotionEvent --- @@ -444,6 +469,16 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, return value; } +ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { + size_t pointerCount = mPointerIds.size(); + for (size_t i = 0; i < pointerCount; i++) { + if (mPointerIds.itemAt(i) == pointerId) { + return i; + } + } + return -1; +} + void MotionEvent::offsetLocation(float xOffset, float yOffset) { mXOffset += xOffset; mYOffset += yOffset; @@ -634,6 +669,208 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { } +// --- VelocityTracker --- + +VelocityTracker::VelocityTracker() { + clear(); +} + +void VelocityTracker::clear() { + mIndex = 0; + mMovements[0].idBits.clear(); + mActivePointerId = -1; +} + +void VelocityTracker::clearPointers(BitSet32 idBits) { + BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); + mMovements[mIndex].idBits = remainingIdBits; + + if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) { + mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1; + } +} + +void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) { + if (++mIndex == HISTORY_SIZE) { + mIndex = 0; + } + + while (idBits.count() > MAX_POINTERS) { + idBits.clearBit(idBits.lastMarkedBit()); + } + + Movement& movement = mMovements[mIndex]; + movement.eventTime = eventTime; + movement.idBits = idBits; + uint32_t count = idBits.count(); + for (uint32_t i = 0; i < count; i++) { + movement.positions[i] = positions[i]; + } + + if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) { + mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1; + } + +#if DEBUG_VELOCITY + LOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d", + eventTime, idBits.value, mActivePointerId); + for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) { + uint32_t id = iterBits.firstMarkedBit(); + uint32_t index = idBits.getIndexOfBit(id); + iterBits.clearBit(id); + float vx, vy; + bool available = getVelocity(id, &vx, &vy); + if (available) { + LOGD(" %d: position (%0.3f, %0.3f), vx=%0.3f, vy=%0.3f, speed=%0.3f", + id, positions[index].x, positions[index].y, vx, vy, sqrtf(vx * vx + vy * vy)); + } else { + assert(vx == 0 && vy == 0); + LOGD(" %d: position (%0.3f, %0.3f), velocity not available", + id, positions[index].x, positions[index].y); + } + } +#endif +} + +void VelocityTracker::addMovement(const MotionEvent* event) { + int32_t actionMasked = event->getActionMasked(); + + switch (actionMasked) { + case AMOTION_EVENT_ACTION_DOWN: + // Clear all pointers on down before adding the new movement. + clear(); + break; + case AMOTION_EVENT_ACTION_POINTER_DOWN: { + // Start a new movement trace for a pointer that just went down. + // We do this on down instead of on up because the client may want to query the + // final velocity for a pointer that just went up. + BitSet32 downIdBits; + downIdBits.markBit(event->getActionIndex()); + clearPointers(downIdBits); + break; + } + case AMOTION_EVENT_ACTION_OUTSIDE: + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_SCROLL: + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_POINTER_UP: + // Ignore these actions because they do not convey any new information about + // pointer movement. We also want to preserve the last known velocity of the pointers. + // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position + // of the pointers that went up. ACTION_POINTER_UP does include the new position of + // pointers that remained down but we will also receive an ACTION_MOVE with this + // information if any of them actually moved. Since we don't know how many pointers + // will be going up at once it makes sense to just wait for the following ACTION_MOVE + // before adding the movement. + return; + } + + size_t pointerCount = event->getPointerCount(); + if (pointerCount > MAX_POINTERS) { + pointerCount = MAX_POINTERS; + } + + BitSet32 idBits; + for (size_t i = 0; i < pointerCount; i++) { + idBits.markBit(event->getPointerId(i)); + } + + nsecs_t eventTime; + Position positions[pointerCount]; + + size_t historySize = event->getHistorySize(); + for (size_t h = 0; h < historySize; h++) { + eventTime = event->getHistoricalEventTime(h); + for (size_t i = 0; i < pointerCount; i++) { + positions[i].x = event->getHistoricalX(i, h); + positions[i].y = event->getHistoricalY(i, h); + } + addMovement(eventTime, idBits, positions); + } + + eventTime = event->getEventTime(); + for (size_t i = 0; i < pointerCount; i++) { + positions[i].x = event->getX(i); + positions[i].y = event->getY(i); + } + addMovement(eventTime, idBits, positions); +} + +bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const { + const Movement& newestMovement = mMovements[mIndex]; + if (newestMovement.idBits.hasBit(id)) { + // Find the oldest sample that contains the pointer and that is not older than MAX_AGE. + nsecs_t minTime = newestMovement.eventTime - MAX_AGE; + uint32_t oldestIndex = mIndex; + uint32_t numTouches = 1; + do { + uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1; + const Movement& nextOldestMovement = mMovements[nextOldestIndex]; + if (!nextOldestMovement.idBits.hasBit(id) + || nextOldestMovement.eventTime < minTime) { + break; + } + oldestIndex = nextOldestIndex; + } while (++numTouches < HISTORY_SIZE); + + // Calculate an exponentially weighted moving average of the velocity estimate + // at different points in time measured relative to the oldest sample. + // This is essentially an IIR filter. Newer samples are weighted more heavily + // than older samples. Samples at equal time points are weighted more or less + // equally. + // + // One tricky problem is that the sample data may be poorly conditioned. + // Sometimes samples arrive very close together in time which can cause us to + // overestimate the velocity at that time point. Most samples might be measured + // 16ms apart but some consecutive samples could be only 0.5sm apart because + // the hardware or driver reports them irregularly or in bursts. + float accumVx = 0; + float accumVy = 0; + uint32_t index = oldestIndex; + uint32_t samplesUsed = 0; + const Movement& oldestMovement = mMovements[oldestIndex]; + const Position& oldestPosition = + oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)]; + nsecs_t lastDuration = 0; + while (numTouches-- > 1) { + if (++index == HISTORY_SIZE) { + index = 0; + } + const Movement& movement = mMovements[index]; + nsecs_t duration = movement.eventTime - oldestMovement.eventTime; + + // If the duration between samples is small, we may significantly overestimate + // the velocity. Consequently, we impose a minimum duration constraint on the + // samples that we include in the calculation. + if (duration >= MIN_DURATION) { + const Position& position = movement.positions[movement.idBits.getIndexOfBit(id)]; + float scale = 1000000000.0f / duration; // one over time delta in seconds + float vx = (position.x - oldestPosition.x) * scale; + float vy = (position.y - oldestPosition.y) * scale; + + accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration); + accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration); + + lastDuration = duration; + samplesUsed += 1; + } + } + + // Make sure we used at least one sample. + if (samplesUsed != 0) { + *outVx = accumVx; + *outVy = accumVy; + return true; + } + } + + // No data available for this pointer. + *outVx = 0; + *outVy = 0; + return false; +} + + // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 5c57a76..9d1b8b9 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -406,7 +406,7 @@ status_t InputPublisher::publishMotionEvent( for (size_t i = 0; i < pointerCount; i++) { mSharedMessage->motion.pointerIds[i] = pointerIds[i]; - mSharedMessage->motion.sampleData[0].coords[i] = pointerCoords[i]; + mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]); } // Cache essential information about the motion event to ensure that a malicious consumer @@ -475,7 +475,7 @@ status_t InputPublisher::appendMotionSample( mMotionEventSampleDataTail->eventTime = eventTime; for (size_t i = 0; i < mMotionEventPointerCount; i++) { - mMotionEventSampleDataTail->coords[i] = pointerCoords[i]; + mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]); } mMotionEventSampleDataTail = newTail; diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index e09e755..6e57d93 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -36,6 +36,7 @@ #include <dirent.h> #include <errno.h> #include <assert.h> +#include <strings.h> using namespace android; @@ -1764,4 +1765,3 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const return mZipPath.size()-1; } - diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp index 18f858b..d5dd126 100644 --- a/libs/utils/Looper.cpp +++ b/libs/utils/Looper.cpp @@ -218,14 +218,10 @@ int Looper::pollInner(int timeoutMillis) { // Adjust the timeout based on when the next message is due. if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (mNextMessageUptime <= now) { - timeoutMillis = 0; - } else { - uint64_t delay = (mNextMessageUptime - now + 999999LL) / 1000000LL; - if (delay < INT_MAX - && (timeoutMillis < 0 || int(delay) < timeoutMillis)) { - timeoutMillis = int(delay); - } + int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime); + if (messageTimeoutMillis >= 0 + && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) { + timeoutMillis = messageTimeoutMillis; } #if DEBUG_POLL_AND_WAKE LOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d", @@ -444,12 +440,11 @@ int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outDat return result; } - nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC); - if (timeoutNanos <= 0) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + timeoutMillis = toMillisecondTimeoutDelay(now, endTime); + if (timeoutMillis == 0) { return ALOOPER_POLL_TIMEOUT; } - - timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL)); } } } diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp index 784f035..64a29f5 100644 --- a/libs/utils/Timers.cpp +++ b/libs/utils/Timers.cpp @@ -26,6 +26,7 @@ #include <sys/time.h> #include <time.h> #include <errno.h> +#include <limits.h> #ifdef HAVE_WIN32_THREADS #include <windows.h> @@ -53,6 +54,23 @@ nsecs_t systemTime(int clock) #endif } +int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) +{ + int timeoutDelayMillis; + if (timeoutTime > referenceTime) { + uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime); + if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) { + timeoutDelayMillis = -1; + } else { + timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL; + } + } else { + timeoutDelayMillis = 0; + } + return timeoutDelayMillis; +} + + /* * =========================================================================== * DurationTimer diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 77e939e..60085b5 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -26,6 +26,8 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.Map; + /** * MediaMetadataRetriever class provides a unified interface for retrieving * frame and meta data from an input media file. @@ -56,7 +58,19 @@ public class MediaMetadataRetriever * @throws IllegalArgumentException If the path is invalid. */ public native void setDataSource(String path) throws IllegalArgumentException; - + + /** + * Sets the data source (URI) to use. Call this + * method before the rest of the methods in this class. This method may be + * time-consuming. + * + * @param uri The URI of the input media. + * @param headers the headers to be sent together with the request for the data + * @throws IllegalArgumentException If the URI is invalid. + */ + public native void setDataSource(String uri, Map<String, String> headers) + throws IllegalArgumentException; + /** * Sets the data source (FileDescriptor) to use. It is the caller's * responsibility to close the file descriptor. It is safe to do so as soon @@ -398,5 +412,25 @@ public class MediaMetadataRetriever * The metadata key to retrieve the music album compilation status. */ public static final int METADATA_KEY_COMPILATION = 15; + /** + * If this key exists the media contains audio content. + */ + public static final int METADATA_KEY_HAS_AUDIO = 16; + /** + * If this key exists the media contains video content. + */ + public static final int METADATA_KEY_HAS_VIDEO = 17; + /** + * If the media contains video, this key retrieves its width. + */ + public static final int METADATA_KEY_VIDEO_WIDTH = 18; + /** + * If the media contains video, this key retrieves its height. + */ + public static final int METADATA_KEY_VIDEO_HEIGHT = 19; + /** + * This key retrieves the average bitrate (in bits/sec), if available. + */ + public static final int METADATA_KEY_BITRATE = 20; // Add more here... } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 8b29ea8..fcbe59e 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -623,6 +623,11 @@ public class MediaPlayer * being played. Note that if a SurfaceTexture is used, the value * set via setScreenOnWhilePlaying has no effect. * + * The timestamps provided by {@link SurfaceTexture#getTimestamp()} for a + * SurfaceTexture set as the video sink have an unspecified zero point, + * and cannot be directly compared between different media sources or different + * instances of the same media source, or across multiple runs of the same + * program. * @hide */ public void setTexture(SurfaceTexture st) { diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 74d65d1..6b9f2fb 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -1585,6 +1585,17 @@ public class MediaScanner private static native final void native_init(); private native final void native_setup(); private native final void native_finalize(); + + /** + * Releases resouces associated with this MediaScanner object. + * It is considered good practice to call this method when + * one is done using the MediaScanner object. After this method + * is called, the MediaScanner object can no longer be used. + */ + public void release() { + native_finalize(); + } + @Override protected void finalize() { mContext.getContentResolver().releaseProvider(mMediaProvider); diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index d3e9a49..39c6d3e 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -573,27 +573,16 @@ public class AudioEffect { * * @param param the identifier of the parameter to set * @param value the new value for the specified parameter - * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE}, - * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or - * {@link #ERROR_DEAD_OBJECT} in case of failure When called, value.length - * indicates the maximum size of the returned parameters value. When - * returning, value.length is updated with the actual size of the - * returned value. + * @return the number of meaningful bytes in value array in case of success or + * {@link #ERROR_BAD_VALUE}, {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} + * or {@link #ERROR_DEAD_OBJECT} in case of failure. * @throws IllegalStateException * @hide */ public int getParameter(byte[] param, byte[] value) throws IllegalStateException { checkState("getParameter()"); - int[] vSize = new int[1]; - vSize[0] = value.length; - int status = native_getParameter(param.length, param, vSize, value); - if (value.length > vSize[0]) { - byte[] resizedValue = new byte[vSize[0]]; - System.arraycopy(value, 0, resizedValue, 0, vSize[0]); - value = resizedValue; - } - return status; + return native_getParameter(param.length, param, value.length, value); } /** @@ -615,6 +604,7 @@ public class AudioEffect { * array of 1 or 2 integers * * @see #getParameter(byte[], byte[]) + * In case of success, returns the number of meaningful integers in value array. * @hide */ public int getParameter(int param, int[] value) @@ -628,9 +618,14 @@ public class AudioEffect { int status = getParameter(p, v); - value[0] = byteArrayToInt(v); - if (v.length > 4) { - value[1] = byteArrayToInt(v, 4); + if (status == 4 || status == 8) { + value[0] = byteArrayToInt(v); + if (status == 8) { + value[1] = byteArrayToInt(v, 4); + } + status /= 4; + } else { + status = ERROR; } return status; } @@ -640,6 +635,7 @@ public class AudioEffect { * array of 1 or 2 short integers * * @see #getParameter(byte[], byte[]) + * In case of success, returns the number of meaningful short integers in value array. * @hide */ public int getParameter(int param, short[] value) @@ -653,9 +649,14 @@ public class AudioEffect { int status = getParameter(p, v); - value[0] = byteArrayToShort(v); - if (v.length > 2) { - value[1] = byteArrayToShort(v, 2); + if (status == 2 || status == 4) { + value[0] = byteArrayToShort(v); + if (status == 4) { + value[1] = byteArrayToShort(v, 2); + } + status /= 2; + } else { + status = ERROR; } return status; } @@ -665,6 +666,7 @@ public class AudioEffect { * the value is also an array of 1 or 2 integers * * @see #getParameter(byte[], byte[]) + * In case of success, the returns the number of meaningful integers in value array. * @hide */ public int getParameter(int[] param, int[] value) @@ -681,9 +683,14 @@ public class AudioEffect { int status = getParameter(p, v); - value[0] = byteArrayToInt(v); - if (v.length > 4) { - value[1] = byteArrayToInt(v, 4); + if (status == 4 || status == 8) { + value[0] = byteArrayToInt(v); + if (status == 8) { + value[1] = byteArrayToInt(v, 4); + } + status /= 4; + } else { + status = ERROR; } return status; } @@ -693,6 +700,7 @@ public class AudioEffect { * the value is an array of 1 or 2 short integers * * @see #getParameter(byte[], byte[]) + * In case of success, returns the number of meaningful short integers in value array. * @hide */ public int getParameter(int[] param, short[] value) @@ -709,9 +717,14 @@ public class AudioEffect { int status = getParameter(p, v); - value[0] = byteArrayToShort(v); - if (v.length > 2) { - value[1] = byteArrayToShort(v, 2); + if (status == 2 || status == 4) { + value[0] = byteArrayToShort(v); + if (status == 4) { + value[1] = byteArrayToShort(v, 2); + } + status /= 2; + } else { + status = ERROR; } return status; } @@ -740,24 +753,14 @@ public class AudioEffect { /** * Send a command to the effect engine. This method is intended to send * proprietary commands to a particular effect implementation. - * + * In case of success, returns the number of meaningful bytes in reply array. + * In case of failure, the returned value is negative and implementation specific. * @hide */ public int command(int cmdCode, byte[] command, byte[] reply) throws IllegalStateException { checkState("command()"); - int[] replySize = new int[1]; - replySize[0] = reply.length; - - int status = native_command(cmdCode, command.length, command, - replySize, reply); - - if (reply.length > replySize[0]) { - byte[] resizedReply = new byte[replySize[0]]; - System.arraycopy(reply, 0, resizedReply, 0, replySize[0]); - reply = resizedReply; - } - return status; + return native_command(cmdCode, command.length, command, reply.length, reply); } // -------------------------------------------------------------------------- @@ -1145,10 +1148,10 @@ public class AudioEffect { int vsize, byte[] value); private native final int native_getParameter(int psize, byte[] param, - int[] vsize, byte[] value); + int vsize, byte[] value); private native final int native_command(int cmdCode, int cmdSize, - byte[] cmdData, int[] repSize, byte[] repData); + byte[] cmdData, int repSize, byte[] repData); private static native Object[] native_query_effects(); @@ -1172,23 +1175,30 @@ public class AudioEffect { * @hide */ public void checkStatus(int status) { - switch (status) { - case AudioEffect.SUCCESS: - break; - case AudioEffect.ERROR_BAD_VALUE: - throw (new IllegalArgumentException( - "AudioEffect: bad parameter value")); - case AudioEffect.ERROR_INVALID_OPERATION: - throw (new UnsupportedOperationException( - "AudioEffect: invalid parameter operation")); - default: - throw (new RuntimeException("AudioEffect: set/get parameter error")); + if (isError(status)) { + switch (status) { + case AudioEffect.ERROR_BAD_VALUE: + throw (new IllegalArgumentException( + "AudioEffect: bad parameter value")); + case AudioEffect.ERROR_INVALID_OPERATION: + throw (new UnsupportedOperationException( + "AudioEffect: invalid parameter operation")); + default: + throw (new RuntimeException("AudioEffect: set/get parameter error")); + } } } /** * @hide */ + public static boolean isError(int status) { + return (status < 0); + } + + /** + * @hide + */ public int byteArrayToInt(byte[] valueBuf) { return byteArrayToInt(valueBuf, 0); diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 2a89a2a..4fd4147 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -22,7 +22,7 @@ LOCAL_SHARED_LIBRARIES := \ libskia \ libui \ libcutils \ - libsurfaceflinger_client \ + libgui \ libstagefright \ libcamera_client \ libsqlite \ diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 3d7dbf9..5d9a3c5 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -37,6 +37,7 @@ struct fields_t { jclass bitmapClazz; jfieldID nativeBitmap; jmethodID createBitmapMethod; + jmethodID createScaledBitmapMethod; jclass configClazz; jmethodID createConfigMethod; }; @@ -76,32 +77,123 @@ static void setRetriever(JNIEnv* env, jobject thiz, int retriever) env->SetIntField(thiz, fields.context, retriever); } -static void android_media_MediaMetadataRetriever_setDataSource(JNIEnv *env, jobject thiz, jstring path) -{ +static void +android_media_MediaMetadataRetriever_setDataSourceAndHeaders( + JNIEnv *env, jobject thiz, jstring path, jobject headers) { LOGV("setDataSource"); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { - jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); + jniThrowException( + env, + "java/lang/IllegalStateException", "No retriever available"); + return; } + if (!path) { - jniThrowException(env, "java/lang/IllegalArgumentException", "Null pointer"); + jniThrowException( + env, "java/lang/IllegalArgumentException", "Null pointer"); + return; } - const char *pathStr = env->GetStringUTFChars(path, NULL); - if (!pathStr) { // OutOfMemoryError exception already thrown + const char *tmp = env->GetStringUTFChars(path, NULL); + if (!tmp) { // OutOfMemoryError exception already thrown return; } + String8 pathStr(tmp); + + env->ReleaseStringUTFChars(path, tmp); + tmp = NULL; + // Don't let somebody trick us in to reading some random block of memory - if (strncmp("mem://", pathStr, 6) == 0) { - jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid pathname"); + if (strncmp("mem://", pathStr.string(), 6) == 0) { + jniThrowException( + env, "java/lang/IllegalArgumentException", "Invalid pathname"); return; } - process_media_retriever_call(env, retriever->setDataSource(pathStr), "java/lang/RuntimeException", "setDataSource failed"); - env->ReleaseStringUTFChars(path, pathStr); + // headers is a Map<String, String>. + // We build a similar KeyedVector out of it. + KeyedVector<String8, String8> headersVector; + if (headers) { + // Get the Map's entry Set. + jclass mapClass = env->FindClass("java/util/Map"); + + jmethodID entrySet = + env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;"); + + jobject set = env->CallObjectMethod(headers, entrySet); + // Obtain an iterator over the Set + jclass setClass = env->FindClass("java/util/Set"); + + jmethodID iterator = + env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;"); + + jobject iter = env->CallObjectMethod(set, iterator); + // Get the Iterator method IDs + jclass iteratorClass = env->FindClass("java/util/Iterator"); + jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); + + jmethodID next = + env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); + + // Get the Entry class method IDs + jclass entryClass = env->FindClass("java/util/Map$Entry"); + + jmethodID getKey = + env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;"); + + jmethodID getValue = + env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;"); + + // Iterate over the entry Set + while (env->CallBooleanMethod(iter, hasNext)) { + jobject entry = env->CallObjectMethod(iter, next); + jstring key = (jstring) env->CallObjectMethod(entry, getKey); + jstring value = (jstring) env->CallObjectMethod(entry, getValue); + + const char* keyStr = env->GetStringUTFChars(key, NULL); + if (!keyStr) { // Out of memory + return; + } + + const char* valueStr = env->GetStringUTFChars(value, NULL); + if (!valueStr) { // Out of memory + return; + } + + headersVector.add(String8(keyStr), String8(valueStr)); + + env->DeleteLocalRef(entry); + env->ReleaseStringUTFChars(key, keyStr); + env->DeleteLocalRef(key); + env->ReleaseStringUTFChars(value, valueStr); + env->DeleteLocalRef(value); + } + + env->DeleteLocalRef(entryClass); + env->DeleteLocalRef(iteratorClass); + env->DeleteLocalRef(iter); + env->DeleteLocalRef(setClass); + env->DeleteLocalRef(set); + env->DeleteLocalRef(mapClass); + } + + process_media_retriever_call( + env, + retriever->setDataSource( + pathStr.string(), headers ? &headersVector : NULL), + + "java/lang/RuntimeException", + "setDataSource failed"); +} + +static void android_media_MediaMetadataRetriever_setDataSource( + JNIEnv *env, jobject thiz, jstring path) { + android_media_MediaMetadataRetriever_setDataSourceAndHeaders( + env, thiz, path, NULL); } static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) @@ -219,12 +311,14 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, SkBitmap::kRGB_565_Config); size_t width, height; + bool swapWidthAndHeight = false; if (videoFrame->mRotationAngle == 90 || videoFrame->mRotationAngle == 270) { - width = videoFrame->mDisplayHeight; - height = videoFrame->mDisplayWidth; + width = videoFrame->mHeight; + height = videoFrame->mWidth; + swapWidthAndHeight = true; } else { - width = videoFrame->mDisplayWidth; - height = videoFrame->mDisplayHeight; + width = videoFrame->mWidth; + height = videoFrame->mHeight; } jobject jBitmap = env->CallStaticObjectMethod( @@ -240,11 +334,30 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, bitmap->lockPixels(); rotate((uint16_t*)bitmap->getPixels(), (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)), - videoFrame->mDisplayWidth, - videoFrame->mDisplayHeight, + videoFrame->mWidth, + videoFrame->mHeight, videoFrame->mRotationAngle); bitmap->unlockPixels(); + if (videoFrame->mDisplayWidth != videoFrame->mWidth || + videoFrame->mDisplayHeight != videoFrame->mHeight) { + size_t displayWidth = videoFrame->mDisplayWidth; + size_t displayHeight = videoFrame->mDisplayHeight; + if (swapWidthAndHeight) { + displayWidth = videoFrame->mDisplayHeight; + displayHeight = videoFrame->mDisplayWidth; + } + LOGV("Bitmap dimension is scaled from %dx%d to %dx%d", + width, height, displayWidth, displayHeight); + jobject scaledBitmap = env->CallStaticObjectMethod(fields.bitmapClazz, + fields.createScaledBitmapMethod, + jBitmap, + displayWidth, + displayHeight, + true); + return scaledBitmap; + } + return jBitmap; } @@ -352,6 +465,15 @@ static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env) "Can't find Bitmap.createBitmap(int, int, Config) method"); return; } + fields.createScaledBitmapMethod = + env->GetStaticMethodID(fields.bitmapClazz, "createScaledBitmap", + "(Landroid/graphics/Bitmap;IIZ)" + "Landroid/graphics/Bitmap;"); + if (fields.createScaledBitmapMethod == NULL) { + jniThrowException(env, "java/lang/RuntimeException", + "Can't find Bitmap.createScaledBitmap(Bitmap, int, int, boolean) method"); + return; + } fields.nativeBitmap = env->GetFieldID(fields.bitmapClazz, "mNativeBitmap", "I"); if (fields.nativeBitmap == NULL) { jniThrowException(env, "java/lang/RuntimeException", @@ -388,6 +510,7 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje // JNI mapping between Java methods and native methods static JNINativeMethod nativeMethods[] = { {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource}, + {"setDataSource", "(Ljava/lang/String;Ljava/util/Map;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders}, {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD}, {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime}, {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata}, diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp index a5176fa..9d7bf2c 100644 --- a/media/jni/android_media_MediaScanner.cpp +++ b/media/jni/android_media_MediaScanner.cpp @@ -1,4 +1,4 @@ -/* //device/libs/media_jni/MediaScanner.cpp +/* ** ** Copyright 2007, The Android Open Source Project ** @@ -15,36 +15,37 @@ ** limitations under the License. */ -#define LOG_TAG "MediaScanner" -#include "utils/Log.h" - -#include <media/mediascanner.h> -#include <stdio.h> -#include <assert.h> -#include <limits.h> -#include <unistd.h> -#include <fcntl.h> -#include <cutils/properties.h> +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaScannerJNI" +#include <utils/Log.h> #include <utils/threads.h> +#include <media/mediascanner.h> +#include <media/stagefright/StagefrightMediaScanner.h> #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" -#include <media/stagefright/StagefrightMediaScanner.h> +using namespace android; -// ---------------------------------------------------------------------------- -using namespace android; +static const char* const kClassMediaScannerClient = + "android/media/MediaScannerClient"; + +static const char* const kClassMediaScanner = + "android/media/MediaScanner"; -// ---------------------------------------------------------------------------- +static const char* const kRunTimeException = + "java/lang/RuntimeException"; + +static const char* const kIllegalArgumentException = + "java/lang/IllegalArgumentException"; struct fields_t { jfieldID context; }; static fields_t fields; - -// ---------------------------------------------------------------------------- +static Mutex sLock; class MyMediaScannerClient : public MediaScannerClient { @@ -56,33 +57,53 @@ public: mHandleStringTagMethodID(0), mSetMimeTypeMethodID(0) { - jclass mediaScannerClientInterface = env->FindClass("android/media/MediaScannerClient"); + LOGV("MyMediaScannerClient constructor"); + jclass mediaScannerClientInterface = + env->FindClass(kClassMediaScannerClient); + if (mediaScannerClientInterface == NULL) { - fprintf(stderr, "android/media/MediaScannerClient not found\n"); - } - else { - mScanFileMethodID = env->GetMethodID(mediaScannerClientInterface, "scanFile", - "(Ljava/lang/String;JJZ)V"); - mHandleStringTagMethodID = env->GetMethodID(mediaScannerClientInterface, "handleStringTag", - "(Ljava/lang/String;Ljava/lang/String;)V"); - mSetMimeTypeMethodID = env->GetMethodID(mediaScannerClientInterface, "setMimeType", - "(Ljava/lang/String;)V"); - mAddNoMediaFolderMethodID = env->GetMethodID(mediaScannerClientInterface, "addNoMediaFolder", - "(Ljava/lang/String;)V"); + LOGE("Class %s not found", kClassMediaScannerClient); + } else { + mScanFileMethodID = env->GetMethodID( + mediaScannerClientInterface, + "scanFile", + "(Ljava/lang/String;JJZ)V"); + + mHandleStringTagMethodID = env->GetMethodID( + mediaScannerClientInterface, + "handleStringTag", + "(Ljava/lang/String;Ljava/lang/String;)V"); + + mSetMimeTypeMethodID = env->GetMethodID( + mediaScannerClientInterface, + "setMimeType", + "(Ljava/lang/String;)V"); + + mAddNoMediaFolderMethodID = env->GetMethodID( + mediaScannerClientInterface, + "addNoMediaFolder", + "(Ljava/lang/String;)V"); } } - + virtual ~MyMediaScannerClient() { + LOGV("MyMediaScannerClient destructor"); mEnv->DeleteGlobalRef(mClient); } - - // returns true if it succeeded, false if an exception occured in the Java code + + // Returns true if it succeeded, false if an exception occured + // in the Java code virtual bool scanFile(const char* path, long long lastModified, long long fileSize, bool isDirectory) { + LOGV("scanFile: path(%s), time(%lld), size(%lld) and isDir(%d)", + path, lastModified, fileSize, isDirectory); + jstring pathStr; - if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false; + if ((pathStr = mEnv->NewStringUTF(path)) == NULL) { + return false; + } mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified, fileSize, isDirectory); @@ -91,25 +112,36 @@ public: return (!mEnv->ExceptionCheck()); } - // returns true if it succeeded, false if an exception occured in the Java code + // Returns true if it succeeded, false if an exception occured + // in the Java code virtual bool handleStringTag(const char* name, const char* value) { + LOGV("handleStringTag: name(%s) and value(%s)", name, value); jstring nameStr, valueStr; - if ((nameStr = mEnv->NewStringUTF(name)) == NULL) return false; - if ((valueStr = mEnv->NewStringUTF(value)) == NULL) return false; + if ((nameStr = mEnv->NewStringUTF(name)) == NULL) { + return false; + } + if ((valueStr = mEnv->NewStringUTF(value)) == NULL) { + return false; + } - mEnv->CallVoidMethod(mClient, mHandleStringTagMethodID, nameStr, valueStr); + mEnv->CallVoidMethod( + mClient, mHandleStringTagMethodID, nameStr, valueStr); mEnv->DeleteLocalRef(nameStr); mEnv->DeleteLocalRef(valueStr); return (!mEnv->ExceptionCheck()); } - // returns true if it succeeded, false if an exception occured in the Java code + // Returns true if it succeeded, false if an exception occured + // in the Java code virtual bool setMimeType(const char* mimeType) { + LOGV("setMimeType: %s", mimeType); jstring mimeTypeStr; - if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) return false; + if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) { + return false; + } mEnv->CallVoidMethod(mClient, mSetMimeTypeMethodID, mimeTypeStr); @@ -117,11 +149,15 @@ public: return (!mEnv->ExceptionCheck()); } - // returns true if it succeeded, false if an exception occured in the Java code + // Returns true if it succeeded, false if an exception occured + // in the Java code virtual bool addNoMediaFolder(const char* path) { + LOGV("addNoMediaFolder: path(%s)", path); jstring pathStr; - if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false; + if ((pathStr = mEnv->NewStringUTF(path)) == NULL) { + return false; + } mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr); @@ -133,33 +169,51 @@ public: private: JNIEnv *mEnv; jobject mClient; - jmethodID mScanFileMethodID; - jmethodID mHandleStringTagMethodID; + jmethodID mScanFileMethodID; + jmethodID mHandleStringTagMethodID; jmethodID mSetMimeTypeMethodID; jmethodID mAddNoMediaFolderMethodID; }; -// ---------------------------------------------------------------------------- - static bool ExceptionCheck(void* env) { + LOGV("ExceptionCheck"); return ((JNIEnv *)env)->ExceptionCheck(); } +// Call this method with sLock hold +static MediaScanner *getNativeScanner_l(JNIEnv* env, jobject thiz) +{ + return (MediaScanner *) env->GetIntField(thiz, fields.context); +} + +// Call this method with sLock hold +static void setNativeScanner_l(JNIEnv* env, jobject thiz, MediaScanner *s) +{ + env->SetIntField(thiz, fields.context, (int)s); +} + static void -android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path, jobject client) +android_media_MediaScanner_processDirectory( + JNIEnv *env, jobject thiz, jstring path, jobject client) { - MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); + LOGV("processDirectory"); + Mutex::Autolock l(sLock); + MediaScanner *mp = getNativeScanner_l(env, thiz); + if (mp == NULL) { + jniThrowException(env, kRunTimeException, "No scanner available"); + return; + } if (path == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + jniThrowException(env, kIllegalArgumentException, NULL); return; } const char *pathStr = env->GetStringUTFChars(path, NULL); if (pathStr == NULL) { // Out of memory - jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + jniThrowException(env, kRunTimeException, "Out of memory"); return; } @@ -169,24 +223,35 @@ android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring p } static void -android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client) +android_media_MediaScanner_processFile( + JNIEnv *env, jobject thiz, jstring path, + jstring mimeType, jobject client) { - MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); + LOGV("processFile"); + + // Lock already hold by processDirectory + MediaScanner *mp = getNativeScanner_l(env, thiz); + if (mp == NULL) { + jniThrowException(env, kRunTimeException, "No scanner available"); + return; + } if (path == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + jniThrowException(env, kIllegalArgumentException, NULL); return; } - + const char *pathStr = env->GetStringUTFChars(path, NULL); if (pathStr == NULL) { // Out of memory - jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + jniThrowException(env, kRunTimeException, "Out of memory"); return; } - const char *mimeTypeStr = (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL); + + const char *mimeTypeStr = + (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL); if (mimeType && mimeTypeStr == NULL) { // Out of memory env->ReleaseStringUTFChars(path, pathStr); - jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + jniThrowException(env, kRunTimeException, "Out of memory"); return; } @@ -199,17 +264,24 @@ android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path, } static void -android_media_MediaScanner_setLocale(JNIEnv *env, jobject thiz, jstring locale) +android_media_MediaScanner_setLocale( + JNIEnv *env, jobject thiz, jstring locale) { - MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); + LOGV("setLocale"); + Mutex::Autolock l(sLock); + MediaScanner *mp = getNativeScanner_l(env, thiz); + if (mp == NULL) { + jniThrowException(env, kRunTimeException, "No scanner available"); + return; + } if (locale == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + jniThrowException(env, kIllegalArgumentException, NULL); return; } const char *localeStr = env->GetStringUTFChars(locale, NULL); if (localeStr == NULL) { // Out of memory - jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + jniThrowException(env, kRunTimeException, "Out of memory"); return; } mp->setLocale(localeStr); @@ -218,12 +290,19 @@ android_media_MediaScanner_setLocale(JNIEnv *env, jobject thiz, jstring locale) } static jbyteArray -android_media_MediaScanner_extractAlbumArt(JNIEnv *env, jobject thiz, jobject fileDescriptor) +android_media_MediaScanner_extractAlbumArt( + JNIEnv *env, jobject thiz, jobject fileDescriptor) { - MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); + LOGV("extractAlbumArt"); + Mutex::Autolock l(sLock); + MediaScanner *mp = getNativeScanner_l(env, thiz); + if (mp == NULL) { + jniThrowException(env, kRunTimeException, "No scanner available"); + return NULL; + } if (fileDescriptor == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + jniThrowException(env, kIllegalArgumentException, NULL); return NULL; } @@ -233,14 +312,14 @@ android_media_MediaScanner_extractAlbumArt(JNIEnv *env, jobject thiz, jobject fi return NULL; } long len = *((long*)data); - + jbyteArray array = env->NewByteArray(len); if (array != NULL) { jbyte* bytes = env->GetByteArrayElements(array, NULL); memcpy(bytes, data + 4, len); env->ReleaseByteArrayElements(array, bytes, 0); } - + done: free(data); // if NewByteArray() returned NULL, an out-of-memory @@ -256,17 +335,18 @@ done: static void android_media_MediaScanner_native_init(JNIEnv *env) { - jclass clazz; - - clazz = env->FindClass("android/media/MediaScanner"); + LOGV("native_init"); + jclass clazz = env->FindClass(kClassMediaScanner); if (clazz == NULL) { - jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaScanner"); + const char* err = "Can't find android/media/MediaScanner"; + jniThrowException(env, kRunTimeException, err); return; } fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); if (fields.context == NULL) { - jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaScanner.mNativeContext"); + const char* err = "Can't find MediaScanner.mNativeContext"; + jniThrowException(env, kRunTimeException, err); return; } } @@ -274,10 +354,11 @@ android_media_MediaScanner_native_init(JNIEnv *env) static void android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz) { + LOGV("native_setup"); MediaScanner *mp = new StagefrightMediaScanner; if (mp == NULL) { - jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + jniThrowException(env, kRunTimeException, "Out of memory"); return; } @@ -287,38 +368,66 @@ android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz) static void android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz) { - MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); - - //printf("##### android_media_MediaScanner_native_finalize: ctx=0x%p\n", ctx); - - if (mp == 0) + LOGV("native_finalize"); + Mutex::Autolock l(sLock); + MediaScanner *mp = getNativeScanner_l(env, thiz); + if (mp == 0) { return; - + } delete mp; + setNativeScanner_l(env, thiz, 0); } -// ---------------------------------------------------------------------------- - static JNINativeMethod gMethods[] = { - {"processDirectory", "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V", - (void *)android_media_MediaScanner_processDirectory}, - {"processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", - (void *)android_media_MediaScanner_processFile}, - {"setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale}, - {"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt}, - {"native_init", "()V", (void *)android_media_MediaScanner_native_init}, - {"native_setup", "()V", (void *)android_media_MediaScanner_native_setup}, - {"native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize}, -}; + { + "processDirectory", + "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V", + (void *)android_media_MediaScanner_processDirectory + }, + + { + "processFile", + "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", + (void *)android_media_MediaScanner_processFile + }, + + { + "setLocale", + "(Ljava/lang/String;)V", + (void *)android_media_MediaScanner_setLocale + }, -static const char* const kClassPathName = "android/media/MediaScanner"; + { + "extractAlbumArt", + "(Ljava/io/FileDescriptor;)[B", + (void *)android_media_MediaScanner_extractAlbumArt + }, + + { + "native_init", + "()V", + (void *)android_media_MediaScanner_native_init + }, + + { + "native_setup", + "()V", + (void *)android_media_MediaScanner_native_setup + }, + + { + "native_finalize", + "()V", + (void *)android_media_MediaScanner_native_finalize + }, +}; // This function only registers the native methods, and is called from // JNI_OnLoad in android_media_MediaPlayer.cpp int register_android_media_MediaScanner(JNIEnv *env) { return AndroidRuntime::registerNativeMethods(env, - "android/media/MediaScanner", gMethods, NELEM(gMethods)); + kClassMediaScanner, gMethods, NELEM(gMethods)); } diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index cb2f0f9..e71e727 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -570,12 +570,11 @@ setParameter_Exit: static jint android_media_AudioEffect_native_getParameter(JNIEnv *env, - jobject thiz, int psize, jbyteArray pJavaParam, - jintArray pJavaValueSize, jbyteArray pJavaValue) { + jobject thiz, jint psize, jbyteArray pJavaParam, + jint vsize, jbyteArray pJavaValue) { // retrieve the AudioEffect object jbyte* lpParam = NULL; jbyte* lpValue = NULL; - jbyte* lpValueSize = NULL; jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; effect_param_t *p; int voffset; @@ -589,7 +588,7 @@ android_media_AudioEffect_native_getParameter(JNIEnv *env, return AUDIOEFFECT_ERROR_NO_INIT; } - if (psize == 0 || pJavaValueSize == NULL || pJavaParam == NULL || pJavaValue == NULL) { + if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) { return AUDIOEFFECT_ERROR_BAD_VALUE; } @@ -607,26 +606,18 @@ android_media_AudioEffect_native_getParameter(JNIEnv *env, goto getParameter_Exit; } - // get the pointer for the value size from the java array - lpValueSize = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValueSize, NULL); - if (lpValueSize == NULL) { - LOGE("getParameter: Error retrieving value size pointer"); - goto getParameter_Exit; - } - voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int); - p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset - + lpValueSize[0]); + p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize); memcpy(p->data, lpParam, psize); p->psize = psize; - p->vsize = lpValueSize[0]; + p->vsize = vsize; lStatus = lpAudioEffect->getParameter(p); if (lStatus == NO_ERROR) { lStatus = p->status; if (lStatus == NO_ERROR) { memcpy(lpValue, p->data + voffset, p->vsize); - lpValueSize[0] = p->vsize; + vsize = p->vsize; } } @@ -640,19 +631,18 @@ getParameter_Exit: if (lpValue != NULL) { env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0); } - if (lpValueSize != NULL) { - env->ReleasePrimitiveArrayCritical(pJavaValueSize, lpValueSize, 0); - } + if (lStatus == NO_ERROR) { + return vsize; + } return translateError(lStatus); } static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz, - jint cmdCode, jint cmdSize, jbyteArray jCmdData, jintArray jReplySize, + jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize, jbyteArray jReplyData) { jbyte* pCmdData = NULL; jbyte* pReplyData = NULL; - jint* pReplySize = NULL; jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; // retrieve the AudioEffect object @@ -665,7 +655,7 @@ static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz, return AUDIOEFFECT_ERROR_NO_INIT; } - if ((cmdSize != 0 && jCmdData == NULL) || (jReplySize != NULL && jReplyData == NULL)) { + if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) { return AUDIOEFFECT_ERROR_BAD_VALUE; } @@ -678,17 +668,8 @@ static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz, } } - // get the pointer for the reply size from the java array - if (jReplySize != NULL) { - pReplySize = (jint *) env->GetPrimitiveArrayCritical(jReplySize, NULL); - if (pReplySize == NULL) { - LOGE("setParameter: Error retrieving reply pointer"); - goto command_Exit; - } - } - // get the pointer for the reply from the java array - if (pReplySize != NULL && pReplySize[0] != 0 && jReplyData != NULL) { + if (replySize != 0 && jReplyData != NULL) { pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL); if (pReplyData == NULL) { LOGE("setParameter: Error retrieving reply pointer"); @@ -699,7 +680,7 @@ static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz, lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode, (uint32_t)cmdSize, pCmdData, - (uint32_t *)pReplySize, + (uint32_t *)&replySize, pReplyData)); command_Exit: @@ -710,10 +691,10 @@ command_Exit: if (pReplyData != NULL) { env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0); } - if (pReplySize != NULL) { - env->ReleasePrimitiveArrayCritical(jReplySize, pReplySize, 0); - } + if (lStatus == NO_ERROR) { + return replySize; + } return lStatus; } @@ -803,8 +784,8 @@ static JNINativeMethod gMethods[] = { {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled}, {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl}, {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter}, - {"native_getParameter", "(I[B[I[B)I", (void *)android_media_AudioEffect_native_getParameter}, - {"native_command", "(II[B[I[B)I", (void *)android_media_AudioEffect_native_command}, + {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter}, + {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command}, {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects}, }; diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk index 6a7116c..69cfe8c 100755 --- a/media/jni/mediaeditor/Android.mk +++ b/media/jni/mediaeditor/Android.mk @@ -55,7 +55,7 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libstagefright \ libstagefright_omx \ - libsurfaceflinger_client \ + libgui \ libvideoeditorplayer @@ -68,9 +68,6 @@ LOCAL_CFLAGS += \ -DUSE_STAGEFRIGHT_READERS \ -DUSE_STAGEFRIGHT_3GPP_READER - -LOCAL_LDFLAGS += -fuse-ld=bfd - LOCAL_STATIC_LIBRARIES := \ libvideoeditor_core \ libstagefright_color_conversion \ @@ -82,10 +79,6 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_MODULE:= libvideoeditor_jni -# Don't prelink this library. For more efficient code, you may want -# to add this library to the prelink map and set this to true. -LOCAL_PRELINK_MODULE := false - LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libeffects/lvm/lib/Android.mk b/media/libeffects/lvm/lib/Android.mk index ff34707..f49267e 100644 --- a/media/libeffects/lvm/lib/Android.mk +++ b/media/libeffects/lvm/lib/Android.mk @@ -105,7 +105,7 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE:= libmusicbundle -LOCAL_PRELINK_MODULE := false + LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/Eq/lib \ @@ -168,7 +168,7 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE:= libreverb -LOCAL_PRELINK_MODULE := false + LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/Reverb/lib \ diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk index 2e9b9b4..99cfdfa 100644 --- a/media/libeffects/lvm/wrapper/Android.mk +++ b/media/libeffects/lvm/wrapper/Android.mk @@ -13,7 +13,7 @@ LOCAL_MODULE:= libbundlewrapper LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx -LOCAL_PRELINK_MODULE := false + LOCAL_STATIC_LIBRARIES += libmusicbundle @@ -47,7 +47,7 @@ LOCAL_MODULE:= libreverbwrapper LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx -LOCAL_PRELINK_MODULE := false + LOCAL_STATIC_LIBRARIES += libreverb diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk index e6ff654..3a0f438 100644 --- a/media/libeffects/visualizer/Android.mk +++ b/media/libeffects/visualizer/Android.mk @@ -25,6 +25,6 @@ endif LOCAL_C_INCLUDES := \ $(call include-path-for, graphics corecg) -LOCAL_PRELINK_MODULE := false + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index fd4c6c6..ca7441a 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -33,11 +33,12 @@ LOCAL_SRC_FILES:= \ IEffectClient.cpp \ AudioEffect.cpp \ Visualizer.cpp \ + MemoryLeakTrackUtil.cpp \ fixedfft.cpp.arm LOCAL_SHARED_LIBRARIES := \ libui libcutils libutils libbinder libsonivox libicuuc libexpat \ - libsurfaceflinger_client libcamera_client libstagefright_foundation \ + libcamera_client libstagefright_foundation \ libgui LOCAL_MODULE:= libmedia diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index a18bedb..cee1c75 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -722,9 +722,12 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) // Manage overrun callback if (mActive && (cblk->framesAvailable() == 0)) { LOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); + AutoMutex _l(cblk->lock); if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { - mCbf(EVENT_OVERRUN, mUserData, 0); cblk->flags |= CBLK_UNDERRUN_ON; + cblk->lock.unlock(); + mCbf(EVENT_OVERRUN, mUserData, 0); + cblk->lock.lock(); } } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 8d8f67b..fb2ee0f 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -329,6 +329,7 @@ void AudioTrack::start() if (mActive == 0) { mActive = 1; mNewPosition = cblk->server + mUpdatePeriod; + cblk->lock.lock(); cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; cblk->flags &= ~CBLK_DISABLED_ON; @@ -339,7 +340,6 @@ void AudioTrack::start() } LOGV("start %p before lock cblk %p", this, mCblk); - cblk->lock.lock(); if (!(cblk->flags & CBLK_INVALID_MSK)) { cblk->lock.unlock(); status = mAudioTrack->start(); @@ -546,12 +546,13 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou } if (loopStart >= loopEnd || - loopEnd - loopStart > cblk->frameCount) { + loopEnd - loopStart > cblk->frameCount || + cblk->server > loopStart) { LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user); return BAD_VALUE; } - if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) { + if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) { LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d", loopStart, loopEnd, cblk->frameCount); return BAD_VALUE; @@ -825,6 +826,12 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) uint32_t framesAvail = cblk->framesAvailable(); + cblk->lock.lock(); + if (cblk->flags & CBLK_INVALID_MSK) { + goto create_new_track; + } + cblk->lock.unlock(); + if (framesAvail == 0) { cblk->lock.lock(); goto start_loop_here; @@ -893,9 +900,14 @@ create_new_track: // restart track if it was disabled by audioflinger due to previous underrun if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { - cblk->flags &= ~CBLK_DISABLED_ON; - LOGW("obtainBuffer() track %p disabled, restarting", this); - mAudioTrack->start(); + AutoMutex _l(cblk->lock); + if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { + cblk->flags &= ~CBLK_DISABLED_ON; + cblk->lock.unlock(); + LOGW("obtainBuffer() track %p disabled, restarting", this); + mAudioTrack->start(); + cblk->lock.lock(); + } } cblk->waitTimeMs = 0; @@ -957,9 +969,10 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) ssize_t written = 0; const int8_t *src = (const int8_t *)buffer; Buffer audioBuffer; + size_t frameSz = (size_t)frameSize(); do { - audioBuffer.frameCount = userSize/frameSize(); + audioBuffer.frameCount = userSize/frameSz; // Calling obtainBuffer() with a negative wait count causes // an (almost) infinite wait time. @@ -991,7 +1004,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) written += toWrite; releaseBuffer(&audioBuffer); - } while (userSize); + } while (userSize >= frameSz); return written; } @@ -1015,12 +1028,15 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) // Manage underrun callback if (mActive && (cblk->framesReady() == 0)) { LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); + AutoMutex _l(cblk->lock); if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { + cblk->flags |= CBLK_UNDERRUN_ON; + cblk->lock.unlock(); mCbf(EVENT_UNDERRUN, mUserData, 0); if (cblk->server == cblk->frameCount) { mCbf(EVENT_BUFFER_END, mUserData, 0); } - cblk->flags |= CBLK_UNDERRUN_ON; + cblk->lock.lock(); if (mSharedBuffer != 0) return false; } } @@ -1139,6 +1155,7 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) fromStart ? "start()" : "obtainBuffer()"); cblk->flags |= CBLK_RESTORING_ON; + // signal old cblk condition so that other threads waiting for available buffers stop // waiting now cblk->cv.broadcast(); @@ -1158,10 +1175,20 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) false); if (result == NO_ERROR) { + // restore write index and set other indexes to reflect empty buffer status + mCblk->user = cblk->user; + mCblk->server = cblk->user; + mCblk->userBase = cblk->user; + mCblk->serverBase = cblk->user; + // restore loop: this is not guaranteed to succeed if new frame count is not + // compatible with loop length + setLoop_l(cblk->loopStart, cblk->loopEnd, cblk->loopCount); if (!fromStart) { mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; } - result = mAudioTrack->start(); + if (mActive) { + result = mAudioTrack->start(); + } if (fromStart && result == NO_ERROR) { mNewPosition = mCblk->server + mUpdatePeriod; } @@ -1279,7 +1306,12 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) this->user = u; // Clear flow control error condition as new data has been written/read to/from buffer. - flags &= ~CBLK_UNDERRUN_MSK; + if (flags & CBLK_UNDERRUN_MSK) { + AutoMutex _l(lock); + if (flags & CBLK_UNDERRUN_MSK) { + flags &= ~CBLK_UNDERRUN_MSK; + } + } return u; } diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp index d5298c9..ebe821f 100644 --- a/media/libmedia/IMediaMetadataRetriever.cpp +++ b/media/libmedia/IMediaMetadataRetriever.cpp @@ -20,6 +20,7 @@ #include <binder/Parcel.h> #include <SkBitmap.h> #include <media/IMediaMetadataRetriever.h> +#include <utils/String8.h> // The binder is supposed to propagate the scheduler group across // the binder interface so that remote calls are executed with @@ -102,11 +103,24 @@ public: remote()->transact(DISCONNECT, data, &reply); } - status_t setDataSource(const char* srcUrl) + status_t setDataSource( + const char *srcUrl, const KeyedVector<String8, String8> *headers) { Parcel data, reply; data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); data.writeCString(srcUrl); + + if (headers == NULL) { + data.writeInt32(0); + } else { + // serialize the headers + data.writeInt32(headers->size()); + for (size_t i = 0; i < headers->size(); ++i) { + data.writeString8(headers->keyAt(i)); + data.writeString8(headers->valueAt(i)); + } + } + remote()->transact(SET_DATA_SOURCE_URL, data, &reply); return reply.readInt32(); } @@ -188,7 +202,18 @@ status_t BnMediaMetadataRetriever::onTransact( case SET_DATA_SOURCE_URL: { CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); const char* srcUrl = data.readCString(); - reply->writeInt32(setDataSource(srcUrl)); + + KeyedVector<String8, String8> headers; + int32_t numHeaders = data.readInt32(); + for (int i = 0; i < numHeaders; ++i) { + String8 key = data.readString8(); + String8 value = data.readString8(); + headers.add(key, value); + } + + reply->writeInt32( + setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL)); + return NO_ERROR; } break; case SET_DATA_SOURCE_FD: { diff --git a/media/libmedia/MemoryLeakTrackUtil.cpp b/media/libmedia/MemoryLeakTrackUtil.cpp new file mode 100644 index 0000000..6a108ae --- /dev/null +++ b/media/libmedia/MemoryLeakTrackUtil.cpp @@ -0,0 +1,169 @@ +/* + * 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. + */ + +#include <media/MemoryLeakTrackUtil.h> + +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> + +/* + * The code here originally resided in MediaPlayerService.cpp and was + * shamelessly copied over to support memory leak tracking from + * multiple places. + */ +namespace android { + +#if defined(__arm__) + +extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, + size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); + +extern "C" void free_malloc_leak_info(uint8_t* info); + +// Use the String-class below instead of String8 to allocate all memory +// beforehand and not reenter the heap while we are examining it... +struct MyString8 { + static const size_t MAX_SIZE = 256 * 1024; + + MyString8() + : mPtr((char *)malloc(MAX_SIZE)) { + *mPtr = '\0'; + } + + ~MyString8() { + free(mPtr); + } + + void append(const char *s) { + strcat(mPtr, s); + } + + const char *string() const { + return mPtr; + } + + size_t size() const { + return strlen(mPtr); + } + +private: + char *mPtr; + + MyString8(const MyString8 &); + MyString8 &operator=(const MyString8 &); +}; + +void dumpMemoryAddresses(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + MyString8 result; + + typedef struct { + size_t size; + size_t dups; + intptr_t * backtrace; + } AllocEntry; + + uint8_t *info = NULL; + size_t overallSize = 0; + size_t infoSize = 0; + size_t totalMemory = 0; + size_t backtraceSize = 0; + + get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); + if (info) { + uint8_t *ptr = info; + size_t count = overallSize / infoSize; + + snprintf(buffer, SIZE, " Allocation count %i\n", count); + result.append(buffer); + snprintf(buffer, SIZE, " Total memory %i\n", totalMemory); + result.append(buffer); + + AllocEntry * entries = new AllocEntry[count]; + + for (size_t i = 0; i < count; i++) { + // Each entry should be size_t, size_t, intptr_t[backtraceSize] + AllocEntry *e = &entries[i]; + + e->size = *reinterpret_cast<size_t *>(ptr); + ptr += sizeof(size_t); + + e->dups = *reinterpret_cast<size_t *>(ptr); + ptr += sizeof(size_t); + + e->backtrace = reinterpret_cast<intptr_t *>(ptr); + ptr += sizeof(intptr_t) * backtraceSize; + } + + // Now we need to sort the entries. They come sorted by size but + // not by stack trace which causes problems using diff. + bool moved; + do { + moved = false; + for (size_t i = 0; i < (count - 1); i++) { + AllocEntry *e1 = &entries[i]; + AllocEntry *e2 = &entries[i+1]; + + bool swap = e1->size < e2->size; + if (e1->size == e2->size) { + for(size_t j = 0; j < backtraceSize; j++) { + if (e1->backtrace[j] == e2->backtrace[j]) { + continue; + } + swap = e1->backtrace[j] < e2->backtrace[j]; + break; + } + } + if (swap) { + AllocEntry t = entries[i]; + entries[i] = entries[i+1]; + entries[i+1] = t; + moved = true; + } + } + } while (moved); + + for (size_t i = 0; i < count; i++) { + AllocEntry *e = &entries[i]; + + snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups); + result.append(buffer); + for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) { + if (ct) { + result.append(", "); + } + snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]); + result.append(buffer); + } + result.append("\n"); + } + + delete[] entries; + free_malloc_leak_info(info); + } + + write(fd, result.string(), result.size()); +} + +#else +// Does nothing +void dumpMemoryAddresses(int fd) {} + +#endif +} // namespace android diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp index 8dfcb3b..cee06ab 100644 --- a/media/libmedia/mediametadataretriever.cpp +++ b/media/libmedia/mediametadataretriever.cpp @@ -92,7 +92,8 @@ void MediaMetadataRetriever::disconnect() } } -status_t MediaMetadataRetriever::setDataSource(const char* srcUrl) +status_t MediaMetadataRetriever::setDataSource( + const char *srcUrl, const KeyedVector<String8, String8> *headers) { LOGV("setDataSource"); Mutex::Autolock _l(mLock); @@ -105,7 +106,7 @@ status_t MediaMetadataRetriever::setDataSource(const char* srcUrl) return UNKNOWN_ERROR; } LOGV("data source (%s)", srcUrl); - return mRetriever->setDataSource(srcUrl); + return mRetriever->setDataSource(srcUrl, headers); } status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length) diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index e65f6d8..fadad28 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -31,8 +31,7 @@ LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ libstagefright \ libstagefright_omx \ - libstagefright_foundation \ - libsurfaceflinger_client \ + libstagefright_foundation \ libgui LOCAL_STATIC_LIBRARIES := \ diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 0156634..5eecbde 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -51,6 +51,7 @@ #include <media/MediaMetadataRetrieverInterface.h> #include <media/Metadata.h> #include <media/AudioTrack.h> +#include <media/MemoryLeakTrackUtil.h> #include <private/android_filesystem_config.h> @@ -392,139 +393,6 @@ static int myTid() { #endif } -#if defined(__arm__) -extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, - size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); -extern "C" void free_malloc_leak_info(uint8_t* info); - -// Use the String-class below instead of String8 to allocate all memory -// beforehand and not reenter the heap while we are examining it... -struct MyString8 { - static const size_t MAX_SIZE = 256 * 1024; - - MyString8() - : mPtr((char *)malloc(MAX_SIZE)) { - *mPtr = '\0'; - } - - ~MyString8() { - free(mPtr); - } - - void append(const char *s) { - strcat(mPtr, s); - } - - const char *string() const { - return mPtr; - } - - size_t size() const { - return strlen(mPtr); - } - -private: - char *mPtr; - - MyString8(const MyString8 &); - MyString8 &operator=(const MyString8 &); -}; - -void memStatus(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - MyString8 result; - - typedef struct { - size_t size; - size_t dups; - intptr_t * backtrace; - } AllocEntry; - - uint8_t *info = NULL; - size_t overallSize = 0; - size_t infoSize = 0; - size_t totalMemory = 0; - size_t backtraceSize = 0; - - get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); - if (info) { - uint8_t *ptr = info; - size_t count = overallSize / infoSize; - - snprintf(buffer, SIZE, " Allocation count %i\n", count); - result.append(buffer); - snprintf(buffer, SIZE, " Total memory %i\n", totalMemory); - result.append(buffer); - - AllocEntry * entries = new AllocEntry[count]; - - for (size_t i = 0; i < count; i++) { - // Each entry should be size_t, size_t, intptr_t[backtraceSize] - AllocEntry *e = &entries[i]; - - e->size = *reinterpret_cast<size_t *>(ptr); - ptr += sizeof(size_t); - - e->dups = *reinterpret_cast<size_t *>(ptr); - ptr += sizeof(size_t); - - e->backtrace = reinterpret_cast<intptr_t *>(ptr); - ptr += sizeof(intptr_t) * backtraceSize; - } - - // Now we need to sort the entries. They come sorted by size but - // not by stack trace which causes problems using diff. - bool moved; - do { - moved = false; - for (size_t i = 0; i < (count - 1); i++) { - AllocEntry *e1 = &entries[i]; - AllocEntry *e2 = &entries[i+1]; - - bool swap = e1->size < e2->size; - if (e1->size == e2->size) { - for(size_t j = 0; j < backtraceSize; j++) { - if (e1->backtrace[j] == e2->backtrace[j]) { - continue; - } - swap = e1->backtrace[j] < e2->backtrace[j]; - break; - } - } - if (swap) { - AllocEntry t = entries[i]; - entries[i] = entries[i+1]; - entries[i+1] = t; - moved = true; - } - } - } while (moved); - - for (size_t i = 0; i < count; i++) { - AllocEntry *e = &entries[i]; - - snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups); - result.append(buffer); - for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) { - if (ct) { - result.append(", "); - } - snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]); - result.append(buffer); - } - result.append("\n"); - } - - delete[] entries; - free_malloc_leak_info(info); - } - - write(fd, result.string(), result.size()); -} -#endif - status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) { const size_t SIZE = 256; @@ -623,7 +491,6 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) result.append("\n"); } -#if defined(__arm__) bool dumpMem = false; for (size_t i = 0; i < args.size(); i++) { if (args[i] == String16("-m")) { @@ -631,9 +498,8 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) } } if (dumpMem) { - memStatus(fd, args); + dumpMemoryAddresses(fd); } -#endif } write(fd, result.string(), result.size()); return NO_ERROR; diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index 5fcf2a7..8f776b4 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -120,7 +120,8 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType) return p; } -status_t MetadataRetrieverClient::setDataSource(const char *url) +status_t MetadataRetrieverClient::setDataSource( + const char *url, const KeyedVector<String8, String8> *headers) { LOGV("setDataSource(%s)", url); Mutex::Autolock lock(mLock); @@ -131,7 +132,7 @@ status_t MetadataRetrieverClient::setDataSource(const char *url) LOGV("player type = %d", playerType); sp<MediaMetadataRetrieverBase> p = createRetriever(playerType); if (p == NULL) return NO_INIT; - status_t ret = p->setDataSource(url); + status_t ret = p->setDataSource(url, headers); if (ret == NO_ERROR) mRetriever = p; return ret; } diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h index b834715..f08f933 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.h +++ b/media/libmediaplayerservice/MetadataRetrieverClient.h @@ -41,7 +41,10 @@ public: // Implements IMediaMetadataRetriever interface // These methods are called in IMediaMetadataRetriever.cpp? virtual void disconnect(); - virtual status_t setDataSource(const char *url); + + 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 sp<IMemory> getFrameAtTime(int64_t timeUs, int option); virtual sp<IMemory> extractAlbumArt(); diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp index ad95fac..aaf2d18 100644 --- a/media/libmediaplayerservice/MidiMetadataRetriever.cpp +++ b/media/libmediaplayerservice/MidiMetadataRetriever.cpp @@ -35,7 +35,8 @@ void MidiMetadataRetriever::clearMetadataValues() mMetadataValues[0][0] = '\0'; } -status_t MidiMetadataRetriever::setDataSource(const char *url) +status_t MidiMetadataRetriever::setDataSource( + const char *url, const KeyedVector<String8, String8> *headers) { LOGV("setDataSource: %s", url? url: "NULL pointer"); Mutex::Autolock lock(mLock); @@ -43,8 +44,7 @@ status_t MidiMetadataRetriever::setDataSource(const char *url) if (mMidiPlayer == 0) { mMidiPlayer = new MidiFile(); } - // TODO: support headers in MetadataRetriever interface! - return mMidiPlayer->setDataSource(url, NULL /* headers */); + return mMidiPlayer->setDataSource(url, headers); } status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length) diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.h b/media/libmediaplayerservice/MidiMetadataRetriever.h index 73ff347..4cee42d 100644 --- a/media/libmediaplayerservice/MidiMetadataRetriever.h +++ b/media/libmediaplayerservice/MidiMetadataRetriever.h @@ -31,7 +31,9 @@ public: MidiMetadataRetriever() {} ~MidiMetadataRetriever() {} - virtual status_t setDataSource(const char *url); + 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 const char* extractMetadata(int keyCode); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 369a3a8..828e008 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -198,18 +198,21 @@ void NuPlayer::Renderer::signalAudioSinkChanged() { } void NuPlayer::Renderer::onDrainAudioQueue() { - uint32_t numFramesPlayed; - CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); - ssize_t numFramesAvailableToWrite = - mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed); + for (;;) { + uint32_t numFramesPlayed; + CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); - CHECK_GE(numFramesAvailableToWrite, 0); + ssize_t numFramesAvailableToWrite = + mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed); - size_t numBytesAvailableToWrite = - numFramesAvailableToWrite * mAudioSink->frameSize(); + size_t numBytesAvailableToWrite = + numFramesAvailableToWrite * mAudioSink->frameSize(); + + if (numBytesAvailableToWrite == 0) { + break; + } - while (numBytesAvailableToWrite > 0) { if (mAudioQueue.empty()) { break; } @@ -264,10 +267,10 @@ void NuPlayer::Renderer::onDrainAudioQueue() { if (entry->mOffset == entry->mBuffer->size()) { entry->mNotifyConsumed->post(); mAudioQueue.erase(mAudioQueue.begin()); + entry = NULL; } - numBytesAvailableToWrite -= copy; mNumFramesWritten += copy / mAudioSink->frameSize(); } diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index 0db3d1d..b10d52c 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -37,7 +37,7 @@ AMRWriter::AMRWriter(const char *filename) mPaused(false), mResumed(false) { - mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC); + mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR); if (mFd >= 0) { mInitCheck = OK; } @@ -269,7 +269,7 @@ status_t AMRWriter::threadFunc() { } if (stoppedPrematurely) { - notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_COMPLETION_STATUS, UNKNOWN_ERROR); + notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, UNKNOWN_ERROR); } close(mFd); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 88069e9..d2e8b46 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -19,6 +19,7 @@ LOCAL_SRC_FILES:= \ ESDS.cpp \ FileSource.cpp \ FLACExtractor.cpp \ + HTTPBase.cpp \ HTTPStream.cpp \ JPEGSource.cpp \ MP3Extractor.cpp \ @@ -69,13 +70,12 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libsonivox \ libvorbisidec \ - libsurfaceflinger_client \ libstagefright_yuv \ libcamera_client \ libdrmframework \ libcrypto \ libssl \ - libgui + libgui \ LOCAL_STATIC_LIBRARIES := \ libstagefright_color_conversion \ @@ -101,6 +101,60 @@ LOCAL_STATIC_LIBRARIES := \ libstagefright_g711dec \ libFLAC \ +################################################################################ + +# 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 + +# See if the user has specified a stack they want to use +HTTP_STACK = $(HTTP) +# We default to the Chrome HTTP stack. +DEFAULT_HTTP = chrome +ALT_HTTP = android + +ifneq ($(HTTP_STACK),chrome) + ifneq ($(HTTP_STACK),android) + # No HTTP stack is specified, pickup the one we want as default. + ifeq ($(USE_ALT_HTTP),true) + HTTP_STACK = $(ALT_HTTP) + else + HTTP_STACK = $(DEFAULT_HTTP) + endif + endif +endif + +ifeq ($(HTTP_STACK),chrome) + +LOCAL_SHARED_LIBRARIES += \ + liblog \ + libicuuc \ + libicui18n \ + libz \ + libdl \ + +LOCAL_STATIC_LIBRARIES += \ + libstagefright_chromium_http \ + libchromium_net \ + libwebcore \ + +ifneq ($(TARGET_SIMULATOR),true) +LOCAL_SHARED_LIBRARIES += libstlport +include external/stlport/libstlport.mk +endif + +LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1 + +endif # ifeq ($(HTTP_STACK),chrome) + +################################################################################ + LOCAL_SHARED_LIBRARIES += \ libstagefright_amrnb_common \ libstagefright_enc_common \ diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index bd04a26..162d2e6 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -280,6 +280,26 @@ void AudioPlayer::AudioCallback(int event, void *info) { buffer->size = numBytesWritten; } +uint32_t AudioPlayer::getNumFramesPendingPlayout() const { + uint32_t numFramesPlayedOut; + status_t err; + + if (mAudioSink != NULL) { + err = mAudioSink->getPosition(&numFramesPlayedOut); + } else { + err = mAudioTrack->getPosition(&numFramesPlayedOut); + } + + if (err != OK || mNumFramesPlayed < numFramesPlayedOut) { + return 0; + } + + // mNumFramesPlayed is the number of frames submitted + // to the audio sink for playback, but not all of them + // may have played out by now. + return mNumFramesPlayed - numFramesPlayedOut; +} + size_t AudioPlayer::fillBuffer(void *data, size_t size) { if (mNumFramesPlayed == 0) { LOGV("AudioCallback"); @@ -342,7 +362,34 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) { if (err != OK) { if (mObserver && !mReachedEOS) { - mObserver->postAudioEOS(); + // We don't want to post EOS right away but only + // after all frames have actually been played out. + + // These are the number of frames submitted to the + // AudioTrack that you haven't heard yet. + uint32_t numFramesPendingPlayout = + getNumFramesPendingPlayout(); + + // These are the number of frames we're going to + // submit to the AudioTrack by returning from this + // callback. + uint32_t numAdditionalFrames = size_done / mFrameSize; + + numFramesPendingPlayout += numAdditionalFrames; + + int64_t timeToCompletionUs = + (1000000ll * numFramesPendingPlayout) / mSampleRate; + + LOGV("total number of frames played: %lld (%lld us)", + (mNumFramesPlayed + numAdditionalFrames), + 1000000ll * (mNumFramesPlayed + numAdditionalFrames) + / mSampleRate); + + LOGV("%d frames left to play, %lld us (%.2f secs)", + numFramesPendingPlayout, + timeToCompletionUs, timeToCompletionUs / 1E6); + + mObserver->postAudioEOS(timeToCompletionUs + mLatencyUs); } mReachedEOS = true; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 37a93a4..7940de0 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -308,7 +308,7 @@ status_t AwesomePlayer::setDataSource_l( return UNKNOWN_ERROR; } - dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient); + dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); if (mDecryptHandle != NULL) { CHECK(mDrmManagerClient); if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { @@ -880,6 +880,17 @@ void AwesomePlayer::notifyVideoSize_l() { cropLeft, cropTop, cropRight, cropBottom); } + int32_t displayWidth; + if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) { + LOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth); + mDisplayWidth = displayWidth; + } + int32_t displayHeight; + if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) { + LOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight); + mDisplayHeight = displayHeight; + } + int32_t usableWidth = cropRight - cropLeft + 1; int32_t usableHeight = cropBottom - cropTop + 1; if (mDisplayWidth != 0) { @@ -1132,7 +1143,6 @@ void AwesomePlayer::seekAudioIfNecessary_l() { mWatchForAudioSeekComplete = true; mWatchForAudioEOS = true; - mSeekNotificationSent = false; if (mDecryptHandle != NULL) { mDrmManagerClient->setPlaybackStatus(mDecryptHandle, @@ -1291,11 +1301,11 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { // If we're playing video only, report seek complete now, // otherwise audio player will notify us later. notifyListener_l(MEDIA_SEEK_COMPLETE); + mSeekNotificationSent = true; } mFlags |= FIRST_FRAME; mSeeking = NO_SEEK; - mSeekNotificationSent = false; if (mDecryptHandle != NULL) { mDrmManagerClient->setPlaybackStatus(mDecryptHandle, @@ -1555,12 +1565,12 @@ void AwesomePlayer::postVideoLagEvent_l() { mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); } -void AwesomePlayer::postCheckAudioStatusEvent_l() { +void AwesomePlayer::postCheckAudioStatusEvent_l(int64_t delayUs) { if (mAudioStatusEventPending) { return; } mAudioStatusEventPending = true; - mQueue.postEvent(mCheckAudioStatusEvent); + mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs); } void AwesomePlayer::onCheckAudioStatus() { @@ -1656,8 +1666,10 @@ status_t AwesomePlayer::finishSetDataSource_l() { if (!strncasecmp("http://", mUri.string(), 7) || !strncasecmp("https://", mUri.string(), 8)) { - mConnectingDataSource = new NuHTTPDataSource( - (mFlags & INCOGNITO) ? NuHTTPDataSource::kFlagIncognito : 0); + mConnectingDataSource = HTTPBase::Create( + (mFlags & INCOGNITO) + ? HTTPBase::kFlagIncognito + : 0); mLock.unlock(); status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); @@ -1746,7 +1758,8 @@ status_t AwesomePlayer::finishSetDataSource_l() { return UNKNOWN_ERROR; } - dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient); + dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); + if (mDecryptHandle != NULL) { CHECK(mDrmManagerClient); if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { @@ -1844,12 +1857,12 @@ uint32_t AwesomePlayer::flags() const { return mExtractorFlags; } -void AwesomePlayer::postAudioEOS() { - postCheckAudioStatusEvent_l(); +void AwesomePlayer::postAudioEOS(int64_t delayUs) { + postCheckAudioStatusEvent_l(delayUs); } void AwesomePlayer::postAudioSeekComplete() { - postCheckAudioStatusEvent_l(); + postCheckAudioStatusEvent_l(0 /* delayUs */); } } // namespace android diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp index 2809df5..c4ed516 100644 --- a/media/libstagefright/DRMExtractor.cpp +++ b/media/libstagefright/DRMExtractor.cpp @@ -41,7 +41,7 @@ namespace android { class DRMSource : public MediaSource { public: DRMSource(const sp<MediaSource> &mediaSource, - DecryptHandle *decryptHandle, + const sp<DecryptHandle> &decryptHandle, DrmManagerClient *managerClient, int32_t trackId, DrmBuffer *ipmpBox); @@ -56,7 +56,7 @@ protected: private: sp<MediaSource> mOriginalMediaSource; - DecryptHandle* mDecryptHandle; + sp<DecryptHandle> mDecryptHandle; DrmManagerClient* mDrmManagerClient; size_t mTrackId; mutable Mutex mDRMLock; @@ -70,7 +70,7 @@ private: //////////////////////////////////////////////////////////////////////////////// DRMSource::DRMSource(const sp<MediaSource> &mediaSource, - DecryptHandle *decryptHandle, + const sp<DecryptHandle> &decryptHandle, DrmManagerClient *managerClient, int32_t trackId, DrmBuffer *ipmpBox) : mOriginalMediaSource(mediaSource), @@ -245,7 +245,7 @@ DRMExtractor::DRMExtractor(const sp<DataSource> &source, const char* mime) mOriginalExtractor->setDrmFlag(true); mOriginalExtractor->getMetaData()->setInt32(kKeyIsDRM, 1); - source->getDrmInfo(&mDecryptHandle, &mDrmManagerClient); + source->getDrmInfo(mDecryptHandle, &mDrmManagerClient); } DRMExtractor::~DRMExtractor() { @@ -281,7 +281,7 @@ sp<MetaData> DRMExtractor::getMetaData() { bool SniffDRM( const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *) { - DecryptHandle *decryptHandle = source->DrmInitialization(); + sp<DecryptHandle> decryptHandle = source->DrmInitialization(); if (decryptHandle != NULL) { if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) { diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 3b38208..b5c51f4 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -21,7 +21,7 @@ #include "include/OggExtractor.h" #include "include/MPEG2TSExtractor.h" #include "include/NuCachedSource2.h" -#include "include/NuHTTPDataSource.h" +#include "include/HTTPBase.h" #include "include/DRMExtractor.h" #include "include/FLACExtractor.h" #include "include/AACExtractor.h" @@ -127,7 +127,7 @@ sp<DataSource> DataSource::CreateFromURI( source = new FileSource(uri + 7); } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) { - sp<NuHTTPDataSource> httpSource = new NuHTTPDataSource; + sp<HTTPBase> httpSource = HTTPBase::Create(); if (httpSource->connect(uri, headers) != OK) { return NULL; } diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp index 02a78c9..f2f3500 100644 --- a/media/libstagefright/FileSource.cpp +++ b/media/libstagefright/FileSource.cpp @@ -125,7 +125,7 @@ status_t FileSource::getSize(off64_t *size) { return OK; } -DecryptHandle* FileSource::DrmInitialization() { +sp<DecryptHandle> FileSource::DrmInitialization() { if (mDrmManagerClient == NULL) { mDrmManagerClient = new DrmManagerClient(); } @@ -147,8 +147,8 @@ DecryptHandle* FileSource::DrmInitialization() { return mDecryptHandle; } -void FileSource::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) { - *handle = mDecryptHandle; +void FileSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) { + handle = mDecryptHandle; *client = mDrmManagerClient; } diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp new file mode 100644 index 0000000..58b17a7 --- /dev/null +++ b/media/libstagefright/HTTPBase.cpp @@ -0,0 +1,45 @@ +/* + * 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 "include/HTTPBase.h" + +#if CHROMIUM_AVAILABLE +#include "include/ChromiumHTTPDataSource.h" +#endif + +#include "include/NuHTTPDataSource.h" + +#include <cutils/properties.h> + +namespace android { + +HTTPBase::HTTPBase() {} + +// static +sp<HTTPBase> HTTPBase::Create(uint32_t flags) { +#if CHROMIUM_AVAILABLE + char value[PROPERTY_VALUE_MAX]; + if (!property_get("media.stagefright.use-chromium", value, NULL) + || (strcasecmp("false", value) && strcmp("0", value))) { + return new ChromiumHTTPDataSource(flags); + } else +#endif + { + return new NuHTTPDataSource(flags); + } +} + +} // namespace android diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 7b96d01..1ca2d6d 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -262,7 +262,7 @@ static const char *FourCC2MIME(uint32_t fourcc) { MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source) : mDataSource(source), - mHaveMetadata(false), + mInitCheck(NO_INIT), mHasVideo(false), mFirstTrack(NULL), mLastTrack(NULL), @@ -361,8 +361,8 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData( } status_t MPEG4Extractor::readMetaData() { - if (mHaveMetadata) { - return OK; + if (mInitCheck != NO_INIT) { + return mInitCheck; } off64_t offset = 0; @@ -370,17 +370,20 @@ status_t MPEG4Extractor::readMetaData() { while ((err = parseChunk(&offset, 0)) == OK) { } - if (mHaveMetadata) { + if (mInitCheck == OK) { if (mHasVideo) { mFileMetaData->setCString(kKeyMIMEType, "video/mp4"); } else { mFileMetaData->setCString(kKeyMIMEType, "audio/mp4"); } - return OK; + mInitCheck = verifyIfStreamable(); + } else { + mInitCheck = err; } - return err; + CHECK_NE(err, (status_t)NO_INIT); + return mInitCheck; } void MPEG4Extractor::setDrmFlag(bool flag) { @@ -755,7 +758,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return err; } } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) { - mHaveMetadata = true; + mInitCheck = OK; if (!mIsDrm) { return UNKNOWN_ERROR; // Return a dummy error. @@ -2077,6 +2080,101 @@ status_t MPEG4Source::read( } } +MPEG4Extractor::Track *MPEG4Extractor::findTrackByMimePrefix( + const char *mimePrefix) { + for (Track *track = mFirstTrack; track != NULL; track = track->next) { + const char *mime; + if (track->meta != NULL + && track->meta->findCString(kKeyMIMEType, &mime) + && !strncasecmp(mime, mimePrefix, strlen(mimePrefix))) { + return track; + } + } + + return NULL; +} + +status_t MPEG4Extractor::verifyIfStreamable() { + if (!(mDataSource->flags() & DataSource::kIsCachingDataSource)) { + return OK; + } + + Track *audio = findTrackByMimePrefix("audio/"); + Track *video = findTrackByMimePrefix("video/"); + + if (audio == NULL || video == NULL) { + return OK; + } + + sp<SampleTable> audioSamples = audio->sampleTable; + sp<SampleTable> videoSamples = video->sampleTable; + + off64_t maxOffsetDiff = 0; + int64_t maxOffsetTimeUs = -1; + + for (uint32_t i = 0; i < videoSamples->countSamples(); ++i) { + off64_t videoOffset; + uint32_t videoTime; + bool isSync; + CHECK_EQ((status_t)OK, videoSamples->getMetaDataForSample( + i, &videoOffset, NULL, &videoTime, &isSync)); + + int64_t videoTimeUs = (int64_t)(videoTime * 1E6 / video->timescale); + + uint32_t reqAudioTime = (videoTimeUs * audio->timescale) / 1000000; + uint32_t j; + if (audioSamples->findSampleAtTime( + reqAudioTime, &j, SampleTable::kFlagClosest) != OK) { + continue; + } + + off64_t audioOffset; + uint32_t audioTime; + CHECK_EQ((status_t)OK, audioSamples->getMetaDataForSample( + j, &audioOffset, NULL, &audioTime)); + + int64_t audioTimeUs = (int64_t)(audioTime * 1E6 / audio->timescale); + + off64_t offsetDiff = videoOffset - audioOffset; + if (offsetDiff < 0) { + offsetDiff = -offsetDiff; + } + +#if 0 + printf("%s%d/%d videoTime %.2f secs audioTime %.2f secs " + "videoOffset %lld audioOffset %lld offsetDiff %lld\n", + isSync ? "*" : " ", + i, + j, + videoTimeUs / 1E6, + audioTimeUs / 1E6, + videoOffset, + audioOffset, + offsetDiff); +#endif + + if (offsetDiff > maxOffsetDiff) { + maxOffsetDiff = offsetDiff; + maxOffsetTimeUs = videoTimeUs; + } + } + +#if 0 + printf("max offset diff: %lld at video time: %.2f secs\n", + maxOffsetDiff, maxOffsetTimeUs / 1E6); +#endif + + if (maxOffsetDiff < 1024 * 1024) { + return OK; + } + + LOGE("This content is not streamable, " + "max offset diff: %lld at video time: %.2f secs", + maxOffsetDiff, maxOffsetTimeUs / 1E6); + + return ERROR_UNSUPPORTED; +} + static bool LegacySniffMPEG4( const sp<DataSource> &source, String8 *mimeType, float *confidence) { uint8_t header[8]; diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 5d6ea7c..e13b67e 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -52,7 +52,7 @@ static const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL; // 10 min class MPEG4Writer::Track { public: - Track(MPEG4Writer *owner, const sp<MediaSource> &source); + Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); ~Track(); @@ -82,6 +82,7 @@ private: bool mIsAvc; bool mIsAudio; bool mIsMPEG4; + int32_t mTrackId; int64_t mTrackDurationUs; // For realtime applications, we need to adjust the media clock @@ -231,7 +232,7 @@ MPEG4Writer::MPEG4Writer(const char *filename) mEstimatedMoovBoxSize(0), mInterleaveDurationUs(1000000) { - mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC); + mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR); if (mFd >= 0) { mInitCheck = OK; } @@ -295,7 +296,12 @@ status_t MPEG4Writer::Track::dump( } status_t MPEG4Writer::addSource(const sp<MediaSource> &source) { - Track *track = new Track(this, source); + Mutex::Autolock l(mLock); + if (mStarted) { + LOGE("Attempt to add source AFTER recording is started"); + return UNKNOWN_ERROR; + } + Track *track = new Track(this, source, mTracks.size()); mTracks.push_back(track); return OK; @@ -945,7 +951,7 @@ size_t MPEG4Writer::numTracks() { //////////////////////////////////////////////////////////////////////////////// MPEG4Writer::Track::Track( - MPEG4Writer *owner, const sp<MediaSource> &source) + MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) : mOwner(owner), mMeta(source->getFormat()), mSource(source), @@ -953,6 +959,7 @@ MPEG4Writer::Track::Track( mPaused(false), mResumed(false), mStarted(false), + mTrackId(trackId), mTrackDurationUs(0), mEstimatedTrackSizeBytes(0), mSamplesHaveSameSize(true), @@ -2030,7 +2037,7 @@ status_t MPEG4Writer::Track::threadEntry() { (OK != checkCodecSpecificData())) { // no codec specific data err = ERROR_MALFORMED; } - mOwner->trackProgressStatus(this, -1, err); + mOwner->trackProgressStatus(mTrackId, -1, err); // Last chunk if (mOwner->numTracks() == 1) { @@ -2077,41 +2084,34 @@ void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { if (mTrackEveryTimeDurationUs > 0 && timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { LOGV("Fire time tracking progress status at %lld us", timeUs); - mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err); + mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); mPreviousTrackTimeUs = timeUs; } } void MPEG4Writer::trackProgressStatus( - const MPEG4Writer::Track* track, int64_t timeUs, status_t err) { + size_t trackId, int64_t timeUs, status_t err) { Mutex::Autolock lock(mLock); - int32_t nTracks = mTracks.size(); - CHECK(nTracks >= 1); - CHECK(nTracks < 64); // Arbitrary number - - int32_t trackNum = 0; - CHECK(trackNum < nTracks); - trackNum <<= 16; + int32_t trackNum = (trackId << 28); // Error notification // Do not consider ERROR_END_OF_STREAM an error if (err != OK && err != ERROR_END_OF_STREAM) { - notify(MEDIA_RECORDER_EVENT_ERROR, - trackNum | MEDIA_RECORDER_ERROR_UNKNOWN, + notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, + trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, err); return; } if (timeUs == -1) { // Send completion notification - notify(MEDIA_RECORDER_EVENT_INFO, - trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS, + notify(MEDIA_RECORDER_TRACK_EVENT_INFO, + trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, err); - return; } else { // Send progress status - notify(MEDIA_RECORDER_EVENT_INFO, - trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS, + notify(MEDIA_RECORDER_TRACK_EVENT_INFO, + trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, timeUs / 1000); } } diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 248b678..3c99d1c 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -481,11 +481,11 @@ void NuCachedSource2::resumeFetchingIfNecessary() { restartPrefetcherIfNecessary_l(true /* ignore low water threshold */); } -DecryptHandle* NuCachedSource2::DrmInitialization() { +sp<DecryptHandle> NuCachedSource2::DrmInitialization() { return mSource->DrmInitialization(); } -void NuCachedSource2::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) { +void NuCachedSource2::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) { mSource->getDrmInfo(handle, client); } diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp index b24343f..73daf12 100644 --- a/media/libstagefright/NuHTTPDataSource.cpp +++ b/media/libstagefright/NuHTTPDataSource.cpp @@ -530,7 +530,7 @@ void NuHTTPDataSource::addBandwidthMeasurement_l( } } -DecryptHandle* NuHTTPDataSource::DrmInitialization() { +sp<DecryptHandle> NuHTTPDataSource::DrmInitialization() { if (mDrmManagerClient == NULL) { mDrmManagerClient = new DrmManagerClient(); } @@ -554,8 +554,8 @@ DecryptHandle* NuHTTPDataSource::DrmInitialization() { return mDecryptHandle; } -void NuHTTPDataSource::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) { - *handle = mDecryptHandle; +void NuHTTPDataSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) { + handle = mDecryptHandle; *client = mDrmManagerClient; } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 3e26a95..a6a34b3 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -2215,13 +2215,15 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) { onPortSettingsChanged(data1); - } else if (data1 == kPortIndexOutput - && data2 == OMX_IndexConfigCommonOutputCrop) { + } else if (data1 == kPortIndexOutput && + (data2 == OMX_IndexConfigCommonOutputCrop || + data2 == OMX_IndexConfigCommonScale)) { sp<MetaData> oldOutputFormat = mOutputFormat; initOutputFormat(mSource->getFormat()); - if (formatHasNotablyChanged(oldOutputFormat, mOutputFormat)) { + if (data2 == OMX_IndexConfigCommonOutputCrop && + formatHasNotablyChanged(oldOutputFormat, mOutputFormat)) { mOutputPortSettingsHaveChanged = true; if (mNativeWindow != NULL) { @@ -2240,6 +2242,39 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { // already invalid, we'll know soon enough. native_window_set_crop(mNativeWindow.get(), &crop); } + } else if (data2 == OMX_IndexConfigCommonScale) { + OMX_CONFIG_SCALEFACTORTYPE scale; + InitOMXParams(&scale); + scale.nPortIndex = kPortIndexOutput; + + // Change display dimension only when necessary. + if (OK == mOMX->getConfig( + mNode, + OMX_IndexConfigCommonScale, + &scale, sizeof(scale))) { + int32_t left, top, right, bottom; + CHECK(mOutputFormat->findRect(kKeyCropRect, + &left, &top, + &right, &bottom)); + + // The scale is in 16.16 format. + // scale 1.0 = 0x010000. When there is no + // need to change the display, skip it. + LOGV("Get OMX_IndexConfigScale: 0x%lx/0x%lx", + scale.xWidth, scale.xHeight); + + if (scale.xWidth != 0x010000) { + mOutputFormat->setInt32(kKeyDisplayWidth, + ((right - left + 1) * scale.xWidth) >> 16); + mOutputPortSettingsHaveChanged = true; + } + + if (scale.xHeight != 0x010000) { + mOutputFormat->setInt32(kKeyDisplayHeight, + ((bottom - top + 1) * scale.xHeight) >> 16); + mOutputPortSettingsHaveChanged = true; + } + } } } break; diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index ea3b801..4095fbf 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -48,7 +48,8 @@ StagefrightMetadataRetriever::~StagefrightMetadataRetriever() { mClient.disconnect(); } -status_t StagefrightMetadataRetriever::setDataSource(const char *uri) { +status_t StagefrightMetadataRetriever::setDataSource( + const char *uri, const KeyedVector<String8, String8> *headers) { LOGV("setDataSource(%s)", uri); mParsedMetaData = false; @@ -56,7 +57,7 @@ status_t StagefrightMetadataRetriever::setDataSource(const char *uri) { delete mAlbumArt; mAlbumArt = NULL; - mSource = DataSource::CreateFromURI(uri); + mSource = DataSource::CreateFromURI(uri, headers); if (mSource == NULL) { return UNKNOWN_ERROR; @@ -231,6 +232,14 @@ static VideoFrame *extractVideoFrameWithCodecFlags( frame->mData = new uint8_t[frame->mSize]; frame->mRotationAngle = rotationAngle; + int32_t displayWidth, displayHeight; + if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) { + frame->mDisplayWidth = displayWidth; + } + if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) { + frame->mDisplayHeight = displayHeight; + } + int32_t srcFormat; CHECK(meta->findInt32(kKeyColorFormat, &srcFormat)); @@ -411,6 +420,12 @@ void StagefrightMetadataRetriever::parseMetaData() { mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); + bool hasAudio = false; + bool hasVideo = false; + int32_t videoWidth = -1; + int32_t videoHeight = -1; + int32_t audioBitrate = -1; + // The overall duration is the duration of the longest track. int64_t maxDurationUs = 0; for (size_t i = 0; i < numTracks; ++i) { @@ -422,12 +437,55 @@ void StagefrightMetadataRetriever::parseMetaData() { maxDurationUs = durationUs; } } + + const char *mime; + if (trackMeta->findCString(kKeyMIMEType, &mime)) { + if (!hasAudio && !strncasecmp("audio/", mime, 6)) { + hasAudio = true; + + if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) { + audioBitrate = -1; + } + } else if (!hasVideo && !strncasecmp("video/", mime, 6)) { + hasVideo = true; + + CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth)); + CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight)); + } + } } // The duration value is a string representing the duration in ms. sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000); mMetaData.add(METADATA_KEY_DURATION, String8(tmp)); + if (hasAudio) { + mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes")); + } + + if (hasVideo) { + mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes")); + + sprintf(tmp, "%d", videoWidth); + mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp)); + + sprintf(tmp, "%d", videoHeight); + mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp)); + } + + if (numTracks == 1 && hasAudio && audioBitrate >= 0) { + sprintf(tmp, "%d", audioBitrate); + mMetaData.add(METADATA_KEY_BITRATE, String8(tmp)); + } else { + off64_t sourceSize; + if (mSource->getSize(&sourceSize) == OK) { + int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs); + + sprintf(tmp, "%lld", avgBitRate); + mMetaData.add(METADATA_KEY_BITRATE, String8(tmp)); + } + } + if (numTracks == 1) { const char *fileMIME; CHECK(meta->findCString(kKeyMIMEType, &fileMIME)); diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index 9332120..e9e5ef9 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -353,8 +353,6 @@ status_t WAVSource::read( return ERROR_END_OF_STREAM; } - mCurrentPos += n; - buffer->set_range(0, n); if (mWaveFormat == WAVE_FORMAT_PCM) { @@ -406,6 +404,7 @@ status_t WAVSource::read( / (mNumChannels * bytesPerSample) / mSampleRate); buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1); + mCurrentPos += n; *out = buffer; diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk new file mode 100644 index 0000000..80b2478 --- /dev/null +++ b/media/libstagefright/chromium_http/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + ChromiumHTTPDataSource.cpp \ + support.cpp \ + +LOCAL_C_INCLUDES:= \ + $(JNI_H_INCLUDE) \ + frameworks/base/media/libstagefright \ + $(TOP)/frameworks/base/include/media/stagefright/openmax \ + external/chromium \ + external/chromium/android + +LOCAL_CFLAGS += -Wno-multichar + +ifneq ($(TARGET_SIMULATOR),true) +LOCAL_SHARED_LIBRARIES += libstlport +include external/stlport/libstlport.mk +endif + +LOCAL_MODULE:= libstagefright_chromium_http + +include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp new file mode 100644 index 0000000..949a5e4 --- /dev/null +++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp @@ -0,0 +1,327 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "ChromiumHTTPDataSource" +#include <media/stagefright/foundation/ADebug.h> + +#include "include/ChromiumHTTPDataSource.h" + +#include <media/stagefright/foundation/ALooper.h> +#include <media/stagefright/MediaErrors.h> + +#include "support.h" + +namespace android { + +ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags) + : mFlags(flags), + mState(DISCONNECTED), + mDelegate(new SfDelegate), + mCurrentOffset(0), + mIOResult(OK), + mContentSize(-1), + mNumBandwidthHistoryItems(0), + mTotalTransferTimeUs(0), + mTotalTransferBytes(0), + mDecryptHandle(NULL), + mDrmManagerClient(NULL) { + mDelegate->setOwner(this); +} + +ChromiumHTTPDataSource::~ChromiumHTTPDataSource() { + disconnect(); + + delete mDelegate; + mDelegate = NULL; + + if (mDrmManagerClient != NULL) { + delete mDrmManagerClient; + mDrmManagerClient = NULL; + } +} + +status_t ChromiumHTTPDataSource::connect( + const char *uri, + const KeyedVector<String8, String8> *headers, + off64_t offset) { + Mutex::Autolock autoLock(mLock); + + return connect_l(uri, headers, offset); +} + +status_t ChromiumHTTPDataSource::connect_l( + const char *uri, + const KeyedVector<String8, String8> *headers, + off64_t offset) { + if (mState != DISCONNECTED) { + disconnect_l(); + } + + if (!(mFlags & kFlagIncognito)) { + LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "connect to %s @%lld", uri, offset); + } else { + LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, + "connect to <URL suppressed> @%lld", offset); + } + + mURI = uri; + + if (headers != NULL) { + mHeaders = *headers; + } else { + mHeaders.clear(); + } + + mState = CONNECTING; + mContentSize = -1; + mCurrentOffset = offset; + + mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset); + + while (mState == CONNECTING) { + mCondition.wait(mLock); + } + + return mState == CONNECTED ? OK : mIOResult; +} + +void ChromiumHTTPDataSource::onConnectionEstablished(int64_t contentSize) { + Mutex::Autolock autoLock(mLock); + mState = CONNECTED; + mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset; + mCondition.broadcast(); +} + +void ChromiumHTTPDataSource::onConnectionFailed(status_t err) { + Mutex::Autolock autoLock(mLock); + mState = DISCONNECTED; + mCondition.broadcast(); + + mURI.clear(); + + mIOResult = err; + + clearDRMState_l(); +} + +void ChromiumHTTPDataSource::disconnect() { + Mutex::Autolock autoLock(mLock); + disconnect_l(); +} + +void ChromiumHTTPDataSource::disconnect_l() { + if (mState == DISCONNECTED) { + return; + } + + mState = DISCONNECTING; + mIOResult = -EINTR; + + mDelegate->initiateDisconnect(); + + while (mState == DISCONNECTING) { + mCondition.wait(mLock); + } + + CHECK_EQ((int)mState, (int)DISCONNECTED); +} + +status_t ChromiumHTTPDataSource::initCheck() const { + Mutex::Autolock autoLock(mLock); + + return mState == CONNECTED ? OK : NO_INIT; +} + +ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) { + Mutex::Autolock autoLock(mLock); + + if (mState != CONNECTED) { + return ERROR_NOT_CONNECTED; + } + + if (offset != mCurrentOffset) { + AString tmp = mURI; + KeyedVector<String8, String8> tmpHeaders = mHeaders; + + disconnect_l(); + + status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset); + + if (err != OK) { + return err; + } + } + + mState = READING; + + int64_t startTimeUs = ALooper::GetNowUs(); + + mDelegate->initiateRead(data, size); + + while (mState == READING) { + mCondition.wait(mLock); + } + + if (mIOResult < OK) { + return mIOResult; + } + + if (mState == CONNECTED) { + int64_t delayUs = ALooper::GetNowUs() - startTimeUs; + + // The read operation was successful, mIOResult contains + // the number of bytes read. + addBandwidthMeasurement_l(mIOResult, delayUs); + + mCurrentOffset += mIOResult; + return mIOResult; + } + + return ERROR_IO; +} + +void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) { + Mutex::Autolock autoLock(mLock); + + mIOResult = size; + + if (mState == READING) { + mState = CONNECTED; + mCondition.broadcast(); + } +} + +status_t ChromiumHTTPDataSource::getSize(off64_t *size) { + Mutex::Autolock autoLock(mLock); + + if (mContentSize < 0) { + return ERROR_UNSUPPORTED; + } + + *size = mContentSize; + + return OK; +} + +uint32_t ChromiumHTTPDataSource::flags() { + return kWantsPrefetching; +} + +// static +void ChromiumHTTPDataSource::InitiateRead( + ChromiumHTTPDataSource *me, void *data, size_t size) { + me->initiateRead(data, size); +} + +void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) { + mDelegate->initiateRead(data, size); +} + +void ChromiumHTTPDataSource::onDisconnectComplete() { + Mutex::Autolock autoLock(mLock); + CHECK_EQ((int)mState, (int)DISCONNECTING); + + mState = DISCONNECTED; + mURI.clear(); + + mCondition.broadcast(); + + clearDRMState_l(); +} + +void ChromiumHTTPDataSource::addBandwidthMeasurement_l( + size_t numBytes, int64_t delayUs) { + BandwidthEntry entry; + entry.mDelayUs = delayUs; + entry.mNumBytes = numBytes; + mTotalTransferTimeUs += delayUs; + mTotalTransferBytes += numBytes; + + mBandwidthHistory.push_back(entry); + if (++mNumBandwidthHistoryItems > 100) { + BandwidthEntry *entry = &*mBandwidthHistory.begin(); + mTotalTransferTimeUs -= entry->mDelayUs; + mTotalTransferBytes -= entry->mNumBytes; + mBandwidthHistory.erase(mBandwidthHistory.begin()); + --mNumBandwidthHistoryItems; + } +} + +bool ChromiumHTTPDataSource::estimateBandwidth(int32_t *bandwidth_bps) { + Mutex::Autolock autoLock(mLock); + + if (mNumBandwidthHistoryItems < 2) { + return false; + } + + *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs); + + return true; +} + +sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() { + Mutex::Autolock autoLock(mLock); + + if (mDrmManagerClient == NULL) { + mDrmManagerClient = new DrmManagerClient(); + } + + if (mDrmManagerClient == NULL) { + return NULL; + } + + if (mDecryptHandle == NULL) { + /* Note if redirect occurs, mUri is the redirect uri instead of the + * original one + */ + mDecryptHandle = mDrmManagerClient->openDecryptSession( + String8(mURI.c_str())); + } + + if (mDecryptHandle == NULL) { + delete mDrmManagerClient; + mDrmManagerClient = NULL; + } + + return mDecryptHandle; +} + +void ChromiumHTTPDataSource::getDrmInfo( + sp<DecryptHandle> &handle, DrmManagerClient **client) { + Mutex::Autolock autoLock(mLock); + + handle = mDecryptHandle; + *client = mDrmManagerClient; +} + +String8 ChromiumHTTPDataSource::getUri() { + Mutex::Autolock autoLock(mLock); + + return String8(mURI.c_str()); +} + +void ChromiumHTTPDataSource::clearDRMState_l() { + if (mDecryptHandle != NULL) { + // To release mDecryptHandle + CHECK(mDrmManagerClient); + mDrmManagerClient->closeDecryptSession(mDecryptHandle); + mDecryptHandle = NULL; + } +} + +} // namespace android + diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp new file mode 100644 index 0000000..7ac56e8 --- /dev/null +++ b/media/libstagefright/chromium_http/support.cpp @@ -0,0 +1,457 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "ChromiumHTTPDataSourceSupport" +#include <utils/Log.h> + +#include <media/stagefright/foundation/AString.h> + +#include "support.h" + +#include "android/net/android_network_library_impl.h" +#include "base/thread.h" +#include "net/base/host_resolver.h" +#include "net/base/ssl_config_service.h" +#include "net/http/http_auth_handler_factory.h" +#include "net/http/http_cache.h" +#include "net/proxy/proxy_config_service_android.h" + +#include "include/ChromiumHTTPDataSource.h" + +#include <cutils/properties.h> +#include <media/stagefright/MediaErrors.h> + +namespace android { + +static Mutex gNetworkThreadLock; +static base::Thread *gNetworkThread = NULL; +static scoped_refptr<URLRequestContext> gReqContext; + +static void InitializeNetworkThreadIfNecessary() { + Mutex::Autolock autoLock(gNetworkThreadLock); + if (gNetworkThread == NULL) { + gNetworkThread = new base::Thread("network"); + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + CHECK(gNetworkThread->StartWithOptions(options)); + + gReqContext = new SfRequestContext; + + net::AndroidNetworkLibrary::RegisterSharedInstance( + new SfNetworkLibrary); + } +} + +static void MY_LOGI(const char *s) { + LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "%s", s); +} + +static void MY_LOGV(const char *s) { +#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0 + LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "%s", s); +#endif +} + +SfNetLog::SfNetLog() + : mNextID(1) { +} + +void SfNetLog::AddEntry( + EventType type, + const base::TimeTicks &time, + const Source &source, + EventPhase phase, + EventParameters *params) { +#if 0 + MY_LOGI(StringPrintf( + "AddEntry time=%s type=%s source=%s phase=%s\n", + TickCountToString(time).c_str(), + EventTypeToString(type), + SourceTypeToString(source.type), + EventPhaseToString(phase)).c_str()); +#endif +} + +uint32 SfNetLog::NextID() { + return mNextID++; +} + +net::NetLog::LogLevel SfNetLog::GetLogLevel() const { + return LOG_ALL; +} + +//////////////////////////////////////////////////////////////////////////////// + +SfRequestContext::SfRequestContext() { + AString ua; + ua.append("stagefright/1.2 (Linux;Android "); + +#if (PROPERTY_VALUE_MAX < 8) +#error "PROPERTY_VALUE_MAX must be at least 8" +#endif + + char value[PROPERTY_VALUE_MAX]; + property_get("ro.build.version.release", value, "Unknown"); + ua.append(value); + ua.append(")"); + + mUserAgent = ua.c_str(); + + net_log_ = new SfNetLog; + + host_resolver_ = + net::CreateSystemHostResolver( + net::HostResolver::kDefaultParallelism, + NULL /* resolver_proc */, + net_log_); + + ssl_config_service_ = + net::SSLConfigService::CreateSystemSSLConfigService(); + + proxy_service_ = net::ProxyService::CreateWithoutProxyResolver( + new net::ProxyConfigServiceAndroid, net_log_); + + http_transaction_factory_ = new net::HttpCache( + host_resolver_, + dnsrr_resolver_, + dns_cert_checker_.get(), + proxy_service_.get(), + ssl_config_service_.get(), + net::HttpAuthHandlerFactory::CreateDefault(host_resolver_), + network_delegate_, + net_log_, + NULL); // backend_factory +} + +const std::string &SfRequestContext::GetUserAgent(const GURL &url) const { + return mUserAgent; +} + +//////////////////////////////////////////////////////////////////////////////// + +SfNetworkLibrary::SfNetworkLibrary() {} + +SfNetworkLibrary::VerifyResult SfNetworkLibrary::VerifyX509CertChain( + const std::vector<std::string>& cert_chain, + const std::string& hostname, + const std::string& auth_type) { + return VERIFY_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +SfDelegate::SfDelegate() + : mOwner(NULL), + mURLRequest(NULL), + mReadBuffer(new net::IOBufferWithSize(8192)), + mNumBytesRead(0), + mNumBytesTotal(0), + mDataDestination(NULL), + mAtEOS(false) { + InitializeNetworkThreadIfNecessary(); +} + +SfDelegate::~SfDelegate() { + CHECK(mURLRequest == NULL); +} + +void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) { + mOwner = owner; +} + +void SfDelegate::OnReceivedRedirect( + URLRequest *request, const GURL &new_url, bool *defer_redirect) { + MY_LOGI("OnReceivedRedirect"); +} + +void SfDelegate::OnAuthRequired( + URLRequest *request, net::AuthChallengeInfo *auth_info) { + MY_LOGI("OnAuthRequired"); + + inherited::OnAuthRequired(request, auth_info); +} + +void SfDelegate::OnCertificateRequested( + URLRequest *request, net::SSLCertRequestInfo *cert_request_info) { + MY_LOGI("OnCertificateRequested"); + + inherited::OnCertificateRequested(request, cert_request_info); +} + +void SfDelegate::OnSSLCertificateError( + URLRequest *request, int cert_error, net::X509Certificate *cert) { + fprintf(stderr, "OnSSLCertificateError cert_error=%d\n", cert_error); + + inherited::OnSSLCertificateError(request, cert_error, cert); +} + +void SfDelegate::OnGetCookies(URLRequest *request, bool blocked_by_policy) { + MY_LOGI("OnGetCookies"); +} + +void SfDelegate::OnSetCookie( + URLRequest *request, + const std::string &cookie_line, + const net::CookieOptions &options, + bool blocked_by_policy) { + MY_LOGI("OnSetCookie"); +} + +void SfDelegate::OnResponseStarted(URLRequest *request) { + if (request->status().status() != URLRequestStatus::SUCCESS) { + MY_LOGI(StringPrintf( + "Request failed with status %d and os_error %d", + request->status().status(), + request->status().os_error()).c_str()); + + delete mURLRequest; + mURLRequest = NULL; + + mOwner->onConnectionFailed(ERROR_IO); + return; + } else if (mRangeRequested && request->GetResponseCode() != 206) { + MY_LOGI(StringPrintf( + "We requested a content range, but server didn't " + "support that. (responded with %d)", + request->GetResponseCode()).c_str()); + + delete mURLRequest; + mURLRequest = NULL; + + mOwner->onConnectionFailed(-EPIPE); + return; + } else if ((request->GetResponseCode() / 100) != 2) { + MY_LOGI(StringPrintf( + "Server responded with http status %d", + request->GetResponseCode()).c_str()); + + delete mURLRequest; + mURLRequest = NULL; + + mOwner->onConnectionFailed(ERROR_IO); + return; + } + + MY_LOGV("OnResponseStarted"); + + std::string headers; + request->GetAllResponseHeaders(&headers); + + MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str()); + + mOwner->onConnectionEstablished(request->GetExpectedContentSize()); +} + +void SfDelegate::OnReadCompleted(URLRequest *request, int bytes_read) { + if (bytes_read == -1) { + MY_LOGI(StringPrintf( + "OnReadCompleted, read failed, status %d", + request->status().status()).c_str()); + + mOwner->onReadCompleted(ERROR_IO); + return; + } + + MY_LOGV(StringPrintf("OnReadCompleted, read %d bytes", bytes_read).c_str()); + + if (bytes_read < 0) { + MY_LOGI(StringPrintf( + "Read failed w/ status %d\n", + request->status().status()).c_str()); + + mOwner->onReadCompleted(ERROR_IO); + return; + } else if (bytes_read == 0) { + mAtEOS = true; + mOwner->onReadCompleted(mNumBytesRead); + return; + } + + CHECK_GT(bytes_read, 0); + CHECK_LE(mNumBytesRead + bytes_read, mNumBytesTotal); + + memcpy((uint8_t *)mDataDestination + mNumBytesRead, + mReadBuffer->data(), + bytes_read); + + mNumBytesRead += bytes_read; + + readMore(request); +} + +void SfDelegate::readMore(URLRequest *request) { + while (mNumBytesRead < mNumBytesTotal) { + size_t copy = mNumBytesTotal - mNumBytesRead; + if (copy > mReadBuffer->size()) { + copy = mReadBuffer->size(); + } + + int n; + if (request->Read(mReadBuffer, copy, &n)) { + MY_LOGV(StringPrintf("Read %d bytes directly.", n).c_str()); + + CHECK_LE((size_t)n, copy); + + memcpy((uint8_t *)mDataDestination + mNumBytesRead, + mReadBuffer->data(), + n); + + mNumBytesRead += n; + + if (n == 0) { + mAtEOS = true; + break; + } + } else { + MY_LOGV("readMore pending read"); + + if (request->status().status() != URLRequestStatus::IO_PENDING) { + MY_LOGI(StringPrintf( + "Direct read failed w/ status %d\n", + request->status().status()).c_str()); + + mOwner->onReadCompleted(ERROR_IO); + return; + } + + return; + } + } + + mOwner->onReadCompleted(mNumBytesRead); +} + +void SfDelegate::initiateConnection( + const char *uri, + const KeyedVector<String8, String8> *headers, + off64_t offset) { + GURL url(uri); + + MessageLoop *loop = gNetworkThread->message_loop(); + loop->PostTask( + FROM_HERE, + NewRunnableFunction( + &SfDelegate::OnInitiateConnectionWrapper, + this, + url, + headers, + offset)); + +} + +// static +void SfDelegate::OnInitiateConnectionWrapper( + SfDelegate *me, GURL url, + const KeyedVector<String8, String8> *headers, + off64_t offset) { + me->onInitiateConnection(url, headers, offset); +} + +void SfDelegate::onInitiateConnection( + const GURL &url, + const KeyedVector<String8, String8> *extra, + off64_t offset) { + CHECK(mURLRequest == NULL); + + mURLRequest = new URLRequest(url, this); + mAtEOS = false; + + mRangeRequested = false; + + if (offset != 0 || extra != NULL) { + net::HttpRequestHeaders headers = + mURLRequest->extra_request_headers(); + + if (offset != 0) { + headers.AddHeaderFromString( + StringPrintf("Range: bytes=%lld-", offset).c_str()); + + mRangeRequested = true; + } + + if (extra != NULL) { + for (size_t i = 0; i < extra->size(); ++i) { + AString s; + s.append(extra->keyAt(i).string()); + s.append(": "); + s.append(extra->valueAt(i).string()); + + headers.AddHeaderFromString(s.c_str()); + } + } + + mURLRequest->SetExtraRequestHeaders(headers); + } + + mURLRequest->set_context(gReqContext); + + mURLRequest->Start(); +} + +void SfDelegate::initiateDisconnect() { + MessageLoop *loop = gNetworkThread->message_loop(); + loop->PostTask( + FROM_HERE, + NewRunnableFunction( + &SfDelegate::OnInitiateDisconnectWrapper, this)); +} + +// static +void SfDelegate::OnInitiateDisconnectWrapper(SfDelegate *me) { + me->onInitiateDisconnect(); +} + +void SfDelegate::onInitiateDisconnect() { + mURLRequest->Cancel(); + + delete mURLRequest; + mURLRequest = NULL; + + mOwner->onDisconnectComplete(); +} + +void SfDelegate::initiateRead(void *data, size_t size) { + MessageLoop *loop = gNetworkThread->message_loop(); + loop->PostTask( + FROM_HERE, + NewRunnableFunction( + &SfDelegate::OnInitiateReadWrapper, this, data, size)); +} + +// static +void SfDelegate::OnInitiateReadWrapper( + SfDelegate *me, void *data, size_t size) { + me->onInitiateRead(data, size); +} + +void SfDelegate::onInitiateRead(void *data, size_t size) { + CHECK(mURLRequest != NULL); + + mNumBytesRead = 0; + mNumBytesTotal = size; + mDataDestination = data; + + if (mAtEOS) { + mOwner->onReadCompleted(0); + return; + } + + readMore(mURLRequest); +} + +} // namespace android + diff --git a/media/libstagefright/chromium_http/support.h b/media/libstagefright/chromium_http/support.h new file mode 100644 index 0000000..634ac93 --- /dev/null +++ b/media/libstagefright/chromium_http/support.h @@ -0,0 +1,159 @@ +/* + * 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 SUPPORT_H_ + +#define SUPPORT_H_ + +#include <assert.h> + +#include "net/base/net_log.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_context.h" +#include "net/base/android_network_library.h" +#include "net/base/io_buffer.h" + +#include <utils/KeyedVector.h> +#include <utils/String8.h> + +namespace android { + +struct SfNetLog : public net::NetLog { + SfNetLog(); + + virtual void AddEntry( + EventType type, + const base::TimeTicks &time, + const Source &source, + EventPhase phase, + EventParameters *params); + + virtual uint32 NextID(); + virtual LogLevel GetLogLevel() const; + +private: + uint32 mNextID; + + DISALLOW_EVIL_CONSTRUCTORS(SfNetLog); +}; + +struct SfRequestContext : public URLRequestContext { + SfRequestContext(); + + virtual const std::string &GetUserAgent(const GURL &url) const; + +private: + std::string mUserAgent; + + DISALLOW_EVIL_CONSTRUCTORS(SfRequestContext); +}; + +// This is required for https support, we don't really verify certificates, +// we accept anything... +struct SfNetworkLibrary : public net::AndroidNetworkLibrary { + SfNetworkLibrary(); + + virtual VerifyResult VerifyX509CertChain( + const std::vector<std::string>& cert_chain, + const std::string& hostname, + const std::string& auth_type); + +private: + DISALLOW_EVIL_CONSTRUCTORS(SfNetworkLibrary); +}; + +struct ChromiumHTTPDataSource; + +struct SfDelegate : public URLRequest::Delegate { + SfDelegate(); + virtual ~SfDelegate(); + + void initiateConnection( + const char *uri, + const KeyedVector<String8, String8> *headers, + off64_t offset); + + void initiateDisconnect(); + void initiateRead(void *data, size_t size); + + void setOwner(ChromiumHTTPDataSource *mOwner); + + virtual void OnReceivedRedirect( + URLRequest *request, const GURL &new_url, bool *defer_redirect); + + virtual void OnAuthRequired( + URLRequest *request, net::AuthChallengeInfo *auth_info); + + virtual void OnCertificateRequested( + URLRequest *request, net::SSLCertRequestInfo *cert_request_info); + + virtual void OnSSLCertificateError( + URLRequest *request, int cert_error, net::X509Certificate *cert); + + virtual void OnGetCookies(URLRequest *request, bool blocked_by_policy); + + virtual void OnSetCookie( + URLRequest *request, + const std::string &cookie_line, + const net::CookieOptions &options, + bool blocked_by_policy); + + virtual void OnResponseStarted(URLRequest *request); + + virtual void OnReadCompleted(URLRequest *request, int bytes_read); + +private: + typedef Delegate inherited; + + ChromiumHTTPDataSource *mOwner; + + URLRequest *mURLRequest; + scoped_refptr<net::IOBufferWithSize> mReadBuffer; + + size_t mNumBytesRead; + size_t mNumBytesTotal; + void *mDataDestination; + + bool mRangeRequested; + bool mAtEOS; + + void readMore(URLRequest *request); + + static void OnInitiateConnectionWrapper( + SfDelegate *me, + GURL url, + const KeyedVector<String8, String8> *headers, + off64_t offset); + + static void OnInitiateDisconnectWrapper(SfDelegate *me); + + static void OnInitiateReadWrapper( + SfDelegate *me, void *data, size_t size); + + void onInitiateConnection( + const GURL &url, + const KeyedVector<String8, String8> *headers, + off64_t offset); + + void onInitiateDisconnect(); + void onInitiateRead(void *data, size_t size); + + DISALLOW_EVIL_CONSTRUCTORS(SfDelegate); +}; + +} // namespace android + +#endif // SUPPORT_H_ diff --git a/media/libstagefright/codecs/aacdec/sbr_dec.cpp b/media/libstagefright/codecs/aacdec/sbr_dec.cpp index 8fcc3ce..8519b17 100644 --- a/media/libstagefright/codecs/aacdec/sbr_dec.cpp +++ b/media/libstagefright/codecs/aacdec/sbr_dec.cpp @@ -1,5 +1,5 @@ /* ------------------------------------------------------------------ - * Copyright (C) 1998-2009 PacketVideo + * Copyright (C) 1998-2010 PacketVideo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -447,7 +447,12 @@ void sbr_dec(Int16 *inPcmData, if (xoverBand > sbrDec->highSubband) { - xoverBand = 32; /* error condition, default to upsampling mode */ + /* + * error condition, default to upsampling mode + * and make sure that the number of bands for xover does + * not exceed the number of high freq bands. + */ + xoverBand = (sbrDec->highSubband > 32)? 32: sbrDec->highSubband; } m = sbrDec->bufReadOffs + i; /* 2 + i */ @@ -558,18 +563,22 @@ void sbr_dec(Int16 *inPcmData, /* * Set Circular buffer for PS hybrid analysis */ + + int32_t *pt_temp = &scratch_mem[2][32]; + for (i = 0, j = 0; i < 3; i++) { - pv_memmove(&scratch_mem[2][32 + j ], + pv_memmove(&pt_temp[ j], hParametricStereoDec->hHybrid->mQmfBufferReal[i], HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferReal)); - pv_memmove(&scratch_mem[2][32 + j + 44], + pv_memmove(&pt_temp[ j + 44], hParametricStereoDec->hHybrid->mQmfBufferImag[i], HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferImag)); j += 88; } + pv_memset((void *)&qmf_PS_generated_Real[hParametricStereoDec->usb], 0, (64 - hParametricStereoDec->usb)*sizeof(*qmf_PS_generated_Real)); @@ -626,19 +635,23 @@ void sbr_dec(Int16 *inPcmData, * Save Circular buffer history used on PS hybrid analysis */ + + pt_temp = &scratch_mem[2][64]; + for (i = 0, j = 0; i < 3; i++) { pv_memmove(hParametricStereoDec->hHybrid->mQmfBufferReal[i], - &scratch_mem[2][ 64 + j ], + &pt_temp[ j], HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferReal)); pv_memmove(hParametricStereoDec->hHybrid->mQmfBufferImag[i], - &scratch_mem[2][ 64 + j + 44], + &pt_temp[ j + 44], HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferImag)); j += 88; } + pv_memmove(hFrameData->V, &circular_buffer_s[0], 1152*sizeof(*circular_buffer_s)); /* @@ -746,7 +759,12 @@ void sbr_dec(Int16 *inPcmData, if (xoverBand > sbrDec->highSubband) { - xoverBand = 32; /* error condition, default to upsampling mode */ + /* + * error condition, default to upsampling mode + * and make sure that the number of bands for xover does + * not exceed the number of high freq bands. + */ + xoverBand = (sbrDec->highSubband > 32)? 32: sbrDec->highSubband; } } else diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk index cda4f9d..f9cc6a3 100644 --- a/media/libstagefright/codecs/aacenc/Android.mk +++ b/media/libstagefright/codecs/aacenc/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) include frameworks/base/media/libstagefright/codecs/common/Config.mk -LOCAL_PRELINK_MODULE := false + LOCAL_SRC_FILES := basic_op/basicop2.c basic_op/oper_32b.c diff --git a/media/libstagefright/codecs/aacenc/SampleCode/AAC_E_SAMPLES.c b/media/libstagefright/codecs/aacenc/SampleCode/AAC_E_SAMPLES.c index 64d012d..774da7b 100644 --- a/media/libstagefright/codecs/aacenc/SampleCode/AAC_E_SAMPLES.c +++ b/media/libstagefright/codecs/aacenc/SampleCode/AAC_E_SAMPLES.c @@ -188,7 +188,7 @@ int main(int argc, char **argv) useData.memflag = VO_IMF_USERMEMOPERATOR;
useData.memData = (VO_PTR)(&moper);
// open encoder dll;
- handle = dlopen("/data/local/tmp/libvoAACEncv7.so", RTLD_NOW);
+ handle = dlopen("libstagefright.so", RTLD_NOW);
if(handle == 0)
{
printf("open dll error......");
diff --git a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk b/media/libstagefright/codecs/aacenc/SampleCode/Android.mk index 52c9c07..ba3f4d2 100644 --- a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk +++ b/media/libstagefright/codecs/aacenc/SampleCode/Android.mk @@ -1,24 +1,25 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := AAC_E_SAMPLES.c - -LOCAL_SRC_FILES += \ - ../../../Common/cmnMemory.c +LOCAL_SRC_FILES := \ + AAC_E_SAMPLES.c \ + ../../common/cmnMemory.c -LOCAL_MODULE := TestvoAACEnc +LOCAL_CFLAGS += $(VO_CFLAGS) -LOCAL_ARM_MODE := arm +LOCAL_MODULE_TAGS := debug + +LOCAL_MODULE := AACEncTest -LOCAL_STATIC_LIBRARIES := +LOCAL_ARM_MODE := arm -LOCAL_SHARED_LIBRARIES := libvoAACEnc +LOCAL_SHARED_LIBRARIES := \ + libstagefright \ + libdl LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/ \ - $(LOCAL_PATH)/../../../Common \ - $(LOCAL_PATH)/../../../Include \ + $(LOCAL_PATH)/ \ + $(LOCAL_PATH)/../../common \ + $(LOCAL_PATH)/../../common/include \ -LOCAL_CFLAGS := $(VO_CFLAGS) - include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/aacenc/SampleCode/eclair/Makefile b/media/libstagefright/codecs/aacenc/SampleCode/eclair/Makefile deleted file mode 100644 index 22c5dc1..0000000 --- a/media/libstagefright/codecs/aacenc/SampleCode/eclair/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -#/*
-#** Copyright 2003-2010, VisualOn, Inc.
-#**
-#** 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.
-#*/
-
-# target6
-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)
-VOTT:= v7
-
-
-# module type
-# please specify the type of your module: lib or exe
-VOMT:= exe
-
-
-# module macros
-# please append the additional macro definitions here for your module if necessary.
-# e.g. -DVISUALON, macro VISUALON defined for your module
-VOMM:= #ARMV5E
-
-
-
-# please specify the name of your module
-VOTARGET:= voAACEncTestv7
-
-
-# please modify here to be sure to see the g1.mk
-include ../../../../Tools/eclair.mk
-
-# dependent libraries.
-VODEPLIBS:=-ldl
-
-# module source
-# please modify here to be sure to see the ms.mk which specifies all source info of your module
-include ../ms.mk
-
-
-# please specify where is the voRelease on your PC, relative path is suggested
-VORELDIR:=../../../../../Release/
-
-
-# please modify here to be sure to see the doit.mk
-include ../../../../Tools/doit.mk
-
diff --git a/media/libstagefright/codecs/aacenc/SampleCode/ms.mk b/media/libstagefright/codecs/aacenc/SampleCode/ms.mk deleted file mode 100644 index 771a569..0000000 --- a/media/libstagefright/codecs/aacenc/SampleCode/ms.mk +++ /dev/null @@ -1,23 +0,0 @@ -#/*
-#** Copyright 2003-2010, VisualOn, Inc.
-#**
-#** 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.
-#*/
-
-# please list all objects needed by your target here
-OBJS:=AAC_E_SAMPLES.o cmnMemory.o
-
-# please list all directories that all source files relative with your module(.h .c .cpp) locate
-VOSRCDIR:=../ ../../../../include ../../../../Common
-
-
diff --git a/media/libstagefright/codecs/aacenc/Tools/doit.mk b/media/libstagefright/codecs/aacenc/Tools/doit.mk deleted file mode 100644 index dea0b0a..0000000 --- a/media/libstagefright/codecs/aacenc/Tools/doit.mk +++ /dev/null @@ -1,133 +0,0 @@ -#/* -# ** Copyright 2003-2010, VisualOn, Inc. -# ** -# ** 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. -# */ - -VERBOSE:=@ - - -VOMT ?= lib - -ifeq ($(VOMT), lib) -LIB_STATIC=$(VOTARGET).a -LIB_DYNAMIC=$(VOTARGET).so -endif - -ifeq ($(VOMT), exe) -TARGET=$(VOTARGET) -endif - -CFLAGS=$(VOCFLAGS) $(addprefix -I, $(VOSRCDIR)) -CPPFLAGS=$(VOCPPFLAGS) $(addprefix -I, $(VOSRCDIR)) -ifneq ($(VOTT), pc) -ASFLAGS=$(VOASFLAGS) $(addprefix -I, $(VOSRCDIR)) -endif - -LDFLAGS:=$(VOLDFLAGS) -VOTEDEPS+=$(VODEPLIBS) -VOTLDEPS+=$(VODEPLIBS) -VOSTCLIBS ?= - -vpath %.c $(VOSRCDIR) -vpath %.cpp $(VOSRCDIR) -ifneq ($(VOTT), pc) -vpath %.s $(VOSRCDIR) -endif - -ifeq ($(VOTT), pc) -BLTDIRS=$(VORELDIR)/Linux/static -BLTDIRD=$(VORELDIR)/Linux/shared -else -BLTDIRS=$(VORELDIR)/Google/$(VONJ)/lib/$(VOTT) -BLTDIRD=$(VORELDIR)/Google/$(VONJ)/so/$(VOTT) -endif - - -.PRECIOUS: $(OBJDIR)/%.o - -ifeq ($(VOMT), lib) -all: mkdirs $(LIB_STATIC) $(LIB_DYNAMIC) -mkdirs: $(OBJDIR) $(BLTDIRS) $(BLTDIRD) -else -all: mkdirs $(TARGET) -mkdirs: $(OBJDIR) -endif - -$(OBJDIR): - @if test ! -d $@; then \ - mkdir -p $@; \ - fi; - -ifeq ($(VOMT), lib) -$(BLTDIRS): - @if test ! -d $@; then \ - mkdir -p $@; \ - fi; -$(BLTDIRD): - @if test ! -d $@; then \ - mkdir -p $@; \ - fi; -endif - - -ifeq ($(VOMT), lib) -$(LIB_STATIC):$(OBJS) - $(AR) cr $@ $(OBJDIR)/*.o $(VOSTCLIBS) - $(RANLIB) $@ -ifneq ($(VODBG), yes) - #$(STRIP) $@ -endif - -$(LIB_DYNAMIC):$(OBJS) - $(GG) $(LDFLAGS) -o $@ $(OBJDIR)/*.o -Wl,--whole-archive $(VOSTCLIBS) -Wl,--no-whole-archive $(VOTLDEPS) -ifneq ($(VODBG), yes) - $(STRIP) $@ -endif - -else - -$(TARGET):$(OBJS) - $(GG) $(LDFLAGS) -o $@ $(OBJDIR)/*.o -Wl,--whole-archive $(VOSTCLIBS) -Wl,--no-whole-archive $(VOTEDEPS) -ifneq ($(VODBG), yes) - $(STRIP) $@ -endif - -endif - - -.SUFFIXES: .c .cpp .s .o -.c.o: - $(VERBOSE) $(CC) $(CFLAGS) -o $(OBJDIR)/$@ -c $< -#%.c:$(OBJDIR)/%.o -# $(VERBOSE) $(CC) $(CFLAGS) -o $@ -c $< -.cpp.o: - $(VERBOSE) $(GG) $(CPPFLAGS) -o $(OBJDIR)/$@ -c $< -ifneq ($(VOTT), pc) -.s.o: - $(VERBOSE) $(AS) $(ASFLAGS) -o $(OBJDIR)/$@ $< -endif - - -.PHONY: clean devel -clean: -ifeq ($(VOMT), lib) - -rm -fr $(OBJDIR) .*.sw* $(VOTARGET).* -else - -rm -fr $(OBJDIR) .*.sw* $(VOTARGET) -endif - -devel: - cp -a $(LIB_STATIC) $(BLTDIRS) - cp -a $(LIB_DYNAMIC) $(BLTDIRD) - diff --git a/media/libstagefright/codecs/aacenc/Tools/eclair.mk b/media/libstagefright/codecs/aacenc/Tools/eclair.mk deleted file mode 100644 index 1688361..0000000 --- a/media/libstagefright/codecs/aacenc/Tools/eclair.mk +++ /dev/null @@ -1,172 +0,0 @@ -#/* -# ** Copyright 2003-2010, VisualOn, Inc. -# ** -# ** 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. -# */ - -# special macro definitions for building -VOPREDEF=-DLINUX -D_LINUX - -VOPRJ ?= -VONJ ?= eclair -VOTT ?= v6 -# control the version to release out -# available: eva(evaluation), rel(release) -VOVER= -ifeq ($(VOVER), eva) -VOPREDEF+=-D__VOVER_EVA__ -endif - -# for debug or not: yes for debug, any other for release -VODBG?=ye - -# for detecting memory leak -VODML= -ifeq ($(VODML), yes) -VOPREDEF+=-DDMEMLEAK -endif - -VOPREDEF+=-D__VOTT_ARM__ -D__VONJ_ECLAIR__ -TCROOTPATH:=/opt/eclair -GCCVER:=4.4.0 -TCPATH:=$(TCROOTPATH)/prebuilt/linux-x86/toolchain/arm-eabi-$(GCCVER) -CCTPRE:=$(TCPATH)/bin/arm-eabi- -AS:=$(CCTPRE)as -AR:=$(CCTPRE)ar -NM:=$(CCTPRE)nm -CC:=$(CCTPRE)gcc -GG:=$(CCTPRE)g++ -LD:=$(CCTPRE)ld -SIZE:=$(CCTPRE)size -STRIP:=$(CCTPRE)strip -RANLIB:=$(CCTPRE)ranlib -OBJCOPY:=$(CCTPRE)objcopy -OBJDUMP:=$(CCTPRE)objdump -READELF:=$(CCTPRE)readelf -STRINGS:=$(CCTPRE)strings - -# target product dependcy -# available: dream, generic -VOTP:=sapphire-open -CCTLIB:=$(TCROOTPATH)/out/target/product/$(VOTP)/obj/lib -CCTINC:=-I$(TCROOTPATH)/system/core/include \ - -I$(TCROOTPATH)/hardware/libhardware/include \ - -I$(TCROOTPATH)/hardware/ril/include \ - -I$(TCROOTPATH)/hardware/libhardware_legacy/include \ - -I$(TCROOTPATH)/dalvik/libnativehelper/include \ - -I$(TCROOTPATH)/dalvik/libnativehelper/include/nativehelper \ - -I$(TCROOTPATH)/frameworks/base/include \ - -I$(TCROOTPATH)/frameworks/base/core/jni \ - -I$(TCROOTPATH)/frameworks/base/libs/audioflinger \ - -I$(TCROOTPATH)/external/skia/include \ - -I$(TCROOTPATH)/out/target/product/$(VOTP)/obj/include \ - -I$(TCROOTPATH)/bionic/libc/arch-arm/include \ - -I$(TCROOTPATH)/bionic/libc/include \ - -I$(TCROOTPATH)/bionic/libstdc++/include \ - -I$(TCROOTPATH)/bionic/libc/kernel/common \ - -I$(TCROOTPATH)/bionic/libc/kernel/arch-arm \ - -I$(TCROOTPATH)/bionic/libm/include \ - -I$(TCROOTPATH)/bionic/libm/include/arm \ - -I$(TCROOTPATH)/bionic/libthread_db/include \ - -I$(TCROOTPATH)/bionic/libm/arm \ - -I$(TCROOTPATH)/bionic/libm \ - -I$(TCROOTPATH)/frameworks/base/include/android_runtime - #-I$(TCROOTPATH)/out/target/product/$(VOTP)/obj/SHARED_LIBRARIES/libm_intermediates - -CCTCFLAGS:=-msoft-float -mthumb-interwork -fno-exceptions -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -fmessage-length=0 -finline-functions -finline-limit=600 -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers -fstrict-aliasing -funswitch-loops -#-fwide-exec-charset=charset=UTF-32 - -# for target exe -TELDFLAGS:=-nostdlib -Bdynamic -Wl,-T,$(TCROOTPATH)/build/core/armelf.x -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,--no-undefined -Wl,-rpath-link=$(CCTLIB) -L$(CCTLIB) - -VOTEDEPS:=$(CCTLIB)/crtbegin_dynamic.o $(CCTLIB)/crtend_android.o $(TCPATH)/lib/gcc/arm-eabi/$(GCCVER)/interwork/libgcc.a -lc -lm - -# for target lib -TLLDFLAGS:=-nostdlib -Wl,-T,$(TCROOTPATH)/build/core/armelf.xsc -Wl,--gc-sections -Wl,-shared,-Bsymbolic -L$(CCTLIB) -Wl,--no-whole-archive -Wl,--no-undefined $(TCPATH)/lib/gcc/arm-eabi/$(GCCVER)/interwork/libgcc.a - -VOTLDEPS:=-lm -lc - - -ifeq ($(VOTT), v4) -VOCFLAGS:=-mtune=arm9tdmi -march=armv4t -VOASFLAGS:=-march=armv4t -mfpu=softfpa -endif - -ifeq ($(VOTT), v5) -VOCFLAGS:=-march=armv5te -VOASFLAGS:=-march=armv5te -mfpu=vfp -endif - -ifeq ($(VOTT), v5x) -VOCFLAGS:=-march=armv5te -mtune=xscale -VOASFLAGS:=-march=armv5te -mfpu=vfp -endif - -ifeq ($(VOTT), v6) -#VOCFLAGS:=-march=armv6 -mtune=arm1136jf-s -#VOASFLAGS:=-march=armv6 -VOCFLAGS:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp -mfloat-abi=softfp -mapcs -mtpcs-leaf-frame -mlong-calls -VOASFLAGS:=-march=armv6j -mcpu=arm1136jf-s -mfpu=arm1136jf-s -mfloat-abi=softfp -mapcs-float -mapcs-reentrant -endif - -# -# global link options -VOLDFLAGS:=-Wl,-x,-X,--as-needed - - -ifeq ($(VOTT), v7) -VOCFLAGS+=-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp -VOASFLAGS+=-march=armv7-a -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -VOLDFLAGS+=-Wl,--fix-cortex-a8 -endif - -#global compiling options for ARM target -ifneq ($(VOTT), pc) -VOASFLAGS+=--strip-local-absolute -R -endif - - -ifeq ($(VODBG), yes) -VOCFLAGS+=-D_DEBUG -g -else -VOCFLAGS+=-DNDEBUG -O3 -endif - -VOCFLAGS+=$(VOPREDEF) $(VOMM) -Wall -fsigned-char -fomit-frame-pointer -fno-leading-underscore -fpic -fPIC -pipe -ftracer -fforce-addr -fno-bounds-check #-fvisibility=hidden #-fvisibility-inlines-hidden ##-ftree-loop-linear -mthumb -nostdinc -dD -fprefetch-loop-arrays - - -ifneq ($(VOTT), pc) -VOCFLAGS+=$(CCTCFLAGS) $(CCTINC) -VOCPPFLAGS:=-fno-rtti $(VOCFLAGS) - -ifeq ($(VOMT), exe) -VOLDFLAGS+=$(TELDFLAGS) -endif - -ifeq ($(VOMT), lib) -VOLDFLAGS+=$(TLLDFLAGS) -endif -else -VOCPPFLAGS:=$(VOCFLAGS) -ifeq ($(VOMT), lib) -VOLDFLAGS+=-shared -endif -endif - -ifeq ($(VODBG), yes) -#VOLDFLAGS:= -endif - -# where to place object files -OBJDIR=obj - diff --git a/media/libstagefright/codecs/aacenc/build/eclair/ARMV5E/Makefile b/media/libstagefright/codecs/aacenc/build/eclair/ARMV5E/Makefile deleted file mode 100644 index b4f63af..0000000 --- a/media/libstagefright/codecs/aacenc/build/eclair/ARMV5E/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -#/*
-#** Copyright 2003-2010, VisualOn, Inc.
-#**
-#** 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.
-#*/
-
-# target6
-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)
-VOTT:= v5
-
-
-# module type
-# please specify the type of your module: lib or exe
-VOMT:= lib
-
-
-# module macros
-# please append the additional macro definitions here for your module if necessary.
-# e.g. -DVISUALON, macro VISUALON defined for your module
-VOMM:= -DARMV5E -DARM_INASM -DARMV5_INASM
-
-
-
-# please specify the name of your module
-VOTARGET:=libvoAACEncv5
-
-
-# please modify here to be sure to see the g1.mk
-include ../../../../../Tools/eclair.mk
-
-# dependent libraries.
-VODEPLIBS:=#-ldl -lstdc++
-
-# module source
-# please modify here to be sure to see the ms.mk which specifies all source info of your module
-include ../../ms.mk
-
-
-# please specify where is the voRelease on your PC, relative path is suggested
-VORELDIR:=../../../../../../Release
-
-
-# please modify here to be sure to see the doit.mk
-include ../../../../../Tools/doit.mk
-
diff --git a/media/libstagefright/codecs/aacenc/build/eclair/ARMV7/Makefile b/media/libstagefright/codecs/aacenc/build/eclair/ARMV7/Makefile deleted file mode 100644 index cdce2c1..0000000 --- a/media/libstagefright/codecs/aacenc/build/eclair/ARMV7/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -#/*
-#** Copyright 2003-2010, VisualOn, Inc.
-#**
-#** 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.
-#*/
-
-# target6
-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)
-VOTT:= v7
-
-
-# module type
-# please specify the type of your module: lib or exe
-VOMT:= lib
-
-
-# module macros
-# please append the additional macro definitions here for your module if necessary.
-# e.g. -DVISUALON, macro VISUALON defined for your module
-VOMM:= -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM
-
-
-
-# please specify the name of your module
-VOTARGET:=libvoAACEncv7
-
-
-# please modify here to be sure to see the g1.mk
-include ../../../../../Tools/eclair.mk
-
-# dependent libraries.
-VODEPLIBS:=#-ldl -lstdc++
-
-# module source
-# please modify here to be sure to see the ms.mk which specifies all source info of your module
-include ../../ms.mk
-
-
-# please specify where is the voRelease on your PC, relative path is suggested
-VORELDIR:=../../../../../../Release
-
-
-# please modify here to be sure to see the doit.mk
-include ../../../../../Tools/doit.mk
-
diff --git a/media/libstagefright/codecs/aacenc/build/eclair/makefile b/media/libstagefright/codecs/aacenc/build/eclair/makefile deleted file mode 100644 index 6bb3c13..0000000 --- a/media/libstagefright/codecs/aacenc/build/eclair/makefile +++ /dev/null @@ -1,40 +0,0 @@ -#/* -#** Copyright 2003-2010, VisualOn, Inc. -#** -#** 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. -#*/ - -# Just acting as Father Makefile of Modules -# please keep the name 'makefile' unchanged - -# Module Subdirs -VOMSD:=$(dir $(shell find . -name 'Makefile')) - -all: - for dir in $(VOMSD); \ - do \ - $(MAKE) -C $$dir; \ - done - -.PHONY:clean devel -clean: - for dir in $(VOMSD); \ - do \ - $(MAKE) -C $$dir clean; \ - done - -devel: - for dir in $(VOMSD); \ - do \ - $(MAKE) -C $$dir devel; \ - done diff --git a/media/libstagefright/codecs/aacenc/build/ms.mk b/media/libstagefright/codecs/aacenc/build/ms.mk deleted file mode 100644 index b67efbc..0000000 --- a/media/libstagefright/codecs/aacenc/build/ms.mk +++ /dev/null @@ -1,42 +0,0 @@ -#/*
-#** Copyright 2003-2010, VisualOn, Inc.
-#**
-#** 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.
-#*/
-
-
-# please list all objects needed by your target here
-OBJS:=basicop2.o oper_32b.o aac_rom.o aacenc.o aacenc_core.o adj_thr.o \
- band_nrg.o bit_cnt.o bitbuffer.o bitenc.o block_switch.o channel_map.o \
- dyn_bits.o grp_data.o interface.o line_pe.o memalign.o ms_stereo.o \
- pre_echo_control.o psy_configuration.o psy_main.o qc_main.o quantize.o sf_estim.o \
- spreading.o stat_bits.o tns.o transform.o
-
-# please list all directories that all source files relative with your module(.h .c .cpp) locate
-VOSRCDIR:=../../../src \
- ../../../inc \
- ../../../basic_op\
- ../../../../../Include
-
-ifeq ($(VOTT), v5)
-OBJS+= AutoCorrelation_v5.o band_nrg_v5.o CalcWindowEnergy_v5.o \
- PrePostMDCT_v5.o R4R8First_v5.o Radix4FFT_v5.o
-VOSRCDIR+= ../../../src/asm/ARMV5E/
-endif
-
-ifeq ($(VOTT), v7)
-OBJS+= AutoCorrelation_v5.o band_nrg_v5.o CalcWindowEnergy_v5.o \
- PrePostMDCT_v7.o R4R8First_v7.o Radix4FFT_v7.o
-VOSRCDIR+= ../../../src/asm/ARMV5E/
-VOSRCDIR+= ../../../src/asm/ARMV7/
-endif
\ No newline at end of file diff --git a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp index fb300da..a11d46b 100644 --- a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp +++ b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "AMRNBDecoder" +#include <utils/Log.h> + #include "AMRNBDecoder.h" #include "gsmamr_dec.h" @@ -154,18 +158,24 @@ status_t AMRNBDecoder::read( const uint8_t *inputPtr = (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); - size_t numBytesRead = + int32_t numBytesRead = AMRDecode(mState, (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f), (UWord8 *)&inputPtr[1], static_cast<int16_t *>(buffer->data()), MIME_IETF); + if (numBytesRead == -1 ) { + LOGE("PV AMR decoder AMRDecode() call failed"); + buffer->release(); + buffer = NULL; + return ERROR_MALFORMED; + } ++numBytesRead; // Include the frame type header byte. buffer->set_range(0, kNumSamplesPerFrame * sizeof(int16_t)); - if (numBytesRead > mInputBuffer->range_length()) { + if (static_cast<size_t>(numBytesRead) > mInputBuffer->range_length()) { // This is bad, should never have happened, but did. Abort now. buffer->release(); diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk index 4293287..5179380 100644 --- a/media/libstagefright/codecs/amrwbenc/Android.mk +++ b/media/libstagefright/codecs/amrwbenc/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) include frameworks/base/media/libstagefright/codecs/common/Config.mk -LOCAL_PRELINK_MODULE := false + LOCAL_SRC_FILES := \ AMRWBEncoder.cpp \ diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c b/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c index 792d3cc..5e71a5b 100644 --- a/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c +++ b/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c @@ -129,7 +129,7 @@ int encode( useData.memData = (VO_PTR)(&moper);
#ifdef LINUX
- handle = dlopen("/data/local/tmp/voAMRWBEnc.so", RTLD_NOW);
+ handle = dlopen("libstagefright.so", RTLD_NOW);
if(handle == 0)
{
printf("open dll error......");
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk index 7edb166..85ddceb 100644 --- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk +++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk @@ -1,26 +1,26 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := AMRWB_E_SAMPLE.c - -LOCAL_SRC_FILES += \ - ../../../Common/cmnMemory.c +LOCAL_SRC_FILES := \ + AMRWB_E_SAMPLE.c \ + ../../common/cmnMemory.c -LOCAL_MODULE := TestvoAMRWBEnc +LOCAL_MODULE_TAGS := debug +LOCAL_MODULE := AMRWBEncTest LOCAL_ARM_MODE := arm -LOCAL_STATIC_LIBRARIES := +LOCAL_CFLAGS := $(VO_CFLAGS) -LOCAL_SHARED_LIBRARIES := libvoAMRWBEnc +LOCAL_SHARED_LIBRARIES := \ + libstagefright \ + libdl LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/ \ - $(LOCAL_PATH)/../../../Common \ - $(LOCAL_PATH)/../../../Include \ + $(LOCAL_PATH)/ \ + $(LOCAL_PATH)/../../common \ + $(LOCAL_PATH)/../../common/include -LOCAL_CFLAGS := $(VO_CFLAGS) - include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/eclair/Makefile b/media/libstagefright/codecs/amrwbenc/SampleCode/eclair/Makefile deleted file mode 100644 index 55b876a..0000000 --- a/media/libstagefright/codecs/amrwbenc/SampleCode/eclair/Makefile +++ /dev/null @@ -1,56 +0,0 @@ -#/*
-# ** Copyright 2003-2010, VisualOn, Inc.
-# **
-# ** 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.
-# */
-
-# target6
-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)
-VOTT:= v6
-
-
-# module type
-# please specify the type of your module: lib or exe
-VOMT:= exe
-
-
-# module macros
-# please append the additional macro definitions here for your module if necessary.
-# e.g. -DVISUALON, macro VISUALON defined for your module
-VOMM:= #ARMV5E
-
-
-
-# please specify the name of your module
-VOTARGET:= voAMRWBEnc_Test
-
-
-# please modify here to be sure to see the g1.mk
-include ../../../../Tools/eclair.mk
-
-# dependent libraries.
-VODEPLIBS:=-ldl
-
-
-# module source
-# please modify here to be sure to see the ms.mk which specifies all source info of your module
-include ../ms.mk
-
-
-# please specify where is the voRelease on your PC, relative path is suggested
-VORELDIR:=../
-
-
-# please modify here to be sure to see the doit.mk
-include ../../../../Tools/doit.mk
-
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/ms.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/ms.mk deleted file mode 100644 index 74e8913..0000000 --- a/media/libstagefright/codecs/amrwbenc/SampleCode/ms.mk +++ /dev/null @@ -1,24 +0,0 @@ -#/*
-# ** Copyright 2003-2010, VisualOn, Inc.
-# **
-# ** 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.
-# */
-# please list all objects needed by your target here
-OBJS:=AMRWB_E_SAMPLE.o cmnMemory.o
-
-# please list all directories that all source files relative with your module(.h .c .cpp) locate
-VOSRCDIR:=../ \
- ../../../../Common \
- ../../../../Include
-
-
diff --git a/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV5E/Makefile b/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV5E/Makefile deleted file mode 100644 index 58fda29..0000000 --- a/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV5E/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -#/*
-# ** Copyright 2003-2010, VisualOn, Inc.
-# **
-# ** 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.
-# */
-
-# target type
-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)
-VOTT:= v5
-
-
-# module type
-# please specify the type of your module: lib or exe
-VOMT:= lib
-
-
-# module macros
-# please append the additional macro definitions here for your module if necessary.
-ifeq ($(VOTT), v5)
-VOMM:=-DARM -DASM_OPT
-endif
-
-# please specify the name of your module
-VOTARGET:= libvoAMRWBEncv5
-
-
-# please modify here to be sure to see the g1.mk
-include ../../../../../Tools/eclair.mk
-
-# dependent libraries.
-VODEPLIBS:=-ldl -lstdc++ -lcutils
-
-# module source
-# please modify here to be sure to see the ms.mk which specifies all source info of your module
-include ../ms.mk
-
-
-# please specify where is the voRelease on your PC, relative path is suggested
-VORELDIR:=../../../../../../Release
-
-# please modify here to be sure to see the doit.mk
-include ../../../../../Tools/doit.mk
-
diff --git a/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV7/Makefile b/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV7/Makefile deleted file mode 100644 index 5686411..0000000 --- a/media/libstagefright/codecs/amrwbenc/build/eclair/ARMV7/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -#/*
-# ** Copyright 2003-2010, VisualOn, Inc.
-# **
-# ** 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.
-# */
-
-# target type
-# available: pc, v4(armv4), v5(armv5), v5x(armv5 xscale), v6(armv6), v7(cortex-a8 neon)
-VOTT:= v7
-
-
-# module type
-# please specify the type of your module: lib or exe
-VOMT:= lib
-
-
-# module macros
-# please append the additional macro definitions here for your module if necessary.
-ifeq ($(VOTT), v7)
-VOMM:=-DARM -DARMV7 -DASM_OPT
-endif
-
-# please specify the name of your module
-VOTARGET:= libvoAMRWBEncv7
-
-
-# please modify here to be sure to see the g1.mk
-include ../../../../../Tools/eclair.mk
-
-# dependent libraries.
-VODEPLIBS:=-ldl -lstdc++ -lcutils
-
-# module source
-# please modify here to be sure to see the ms.mk which specifies all source info of your module
-include ../ms.mk
-
-
-# please specify where is the voRelease on your PC, relative path is suggested
-VORELDIR:=../../../../../../Release
-
-# please modify here to be sure to see the doit.mk
-include ../../../../../Tools/doit.mk
-
diff --git a/media/libstagefright/codecs/amrwbenc/build/eclair/makefile b/media/libstagefright/codecs/amrwbenc/build/eclair/makefile deleted file mode 100644 index 3473a1a..0000000 --- a/media/libstagefright/codecs/amrwbenc/build/eclair/makefile +++ /dev/null @@ -1,39 +0,0 @@ -#/* -# ** Copyright 2003-2010, VisualOn, Inc. -# ** -# ** 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. -# */ -# Just acting as Father Makefile of Modules -# please keep the name 'makefile' unchanged - -# Module Subdirs -VOMSD:=$(dir $(shell find . -name 'Makefile')) - -all: - for dir in $(VOMSD); \ - do \ - $(MAKE) -C $$dir; \ - done - -.PHONY:clean devel -clean: - for dir in $(VOMSD); \ - do \ - $(MAKE) -C $$dir clean; \ - done - -devel: - for dir in $(VOMSD); \ - do \ - $(MAKE) -C $$dir devel; \ - done diff --git a/media/libstagefright/codecs/amrwbenc/build/eclair/ms.mk b/media/libstagefright/codecs/amrwbenc/build/eclair/ms.mk deleted file mode 100644 index bd6620c..0000000 --- a/media/libstagefright/codecs/amrwbenc/build/eclair/ms.mk +++ /dev/null @@ -1,43 +0,0 @@ -#/*
-# ** Copyright 2003-2010, VisualOn, Inc.
-# **
-# ** 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.
-# */
-# please list all directories that all source files relative with your module(.h .c .cpp) locate
-VOSRCDIR:=../../../inc \
- ../../../src \
- ../../../../../Include
-
-# please list all objects needed by your target here
-OBJS:= autocorr.o az_isp.o bits.o c2t64fx.o c4t64fx.o convolve.o cor_h_x.o decim54.o \
- deemph.o dtx.o g_pitch.o gpclip.o homing.o hp400.o hp50.o hp6k.o hp_wsp.o \
- int_lpc.o isp_az.o isp_isf.o lag_wind.o levinson.o log2.o lp_dec2.o math_op.o mem_align.o \
- oper_32b.o p_med_ol.o pit_shrp.o pitch_f4.o pred_lt4.o preemph.o q_gain2.o q_pulse.o \
- qisf_ns.o qpisf_2s.o random.o residu.o scale.o stream.o syn_filt.o updt_tar.o util.o \
- voAMRWBEnc.o voicefac.o wb_vad.o weight_a.o
-
-
-ifeq ($(VOTT), v5)
-OBJS += cor_h_vec_opt.o Deemph_32_opt.o Dot_p_opt.o Filt_6k_7k_opt.o residu_asm_opt.o \
- scale_sig_opt.o Syn_filt_32_opt.o syn_filt_opt.o pred_lt4_1_opt.o convolve_opt.o \
- Norm_Corr_opt.o
-VOSRCDIR+= ../../../src/asm/ARMV5E
-endif
-
-ifeq ($(VOTT), v7)
-OBJS+= cor_h_vec_neon.o Deemph_32_neon.o Dot_p_neon.o Filt_6k_7k_neon.o residu_asm_neon.o \
- scale_sig_neon.o Syn_filt_32_neon.o syn_filt_neon.o pred_lt4_1_neon.o convolve_neon.o \
- Norm_Corr_neon.o
-VOSRCDIR+= ../../../src/asm/ARMV7
-endif
-
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp index 5bbba35..490129f 100644 --- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp +++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp @@ -534,7 +534,8 @@ status_t AVCDecoder::read( default: { LOGE("Should not be here, unknown nalType %d", nalType); - CHECK(!"Should not be here"); + + err = ERROR_MALFORMED; break; } } diff --git a/media/libstagefright/codecs/common/Android.mk b/media/libstagefright/codecs/common/Android.mk index fffb2ad..af8795a 100644 --- a/media/libstagefright/codecs/common/Android.mk +++ b/media/libstagefright/codecs/common/Android.mk @@ -1,7 +1,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_PRELINK_MODULE := false + LOCAL_SRC_FILES := cmnMemory.c diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp index 59dd740..0ba42ff 100644 --- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp +++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "MP3Decoder" + #include "MP3Decoder.h" #include "include/pvmp3decoder_api.h" @@ -175,7 +178,12 @@ status_t MP3Decoder::read( != NO_DECODING_ERROR) { LOGV("mp3 decoder returned error %d", decoderErr); - if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) { + if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR || + mConfig->outputFrameSize == 0) { + + if (mConfig->outputFrameSize == 0) { + LOGE("Output frame size is 0"); + } buffer->release(); buffer = NULL; diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk index 4e07f6f..d5025a1 100644 --- a/media/libstagefright/foundation/Android.mk +++ b/media/libstagefright/foundation/Android.mk @@ -25,6 +25,6 @@ LOCAL_CFLAGS += -Wno-multichar LOCAL_MODULE:= libstagefright_foundation -LOCAL_PRELINK_MODULE:= false + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index f0cd6a0..8e1bdf3 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -23,7 +23,7 @@ #include "LiveDataSource.h" #include "include/M3UParser.h" -#include "include/NuHTTPDataSource.h" +#include "include/HTTPBase.h" #include <cutils/properties.h> #include <media/stagefright/foundation/hexdump.h> @@ -45,9 +45,9 @@ LiveSession::LiveSession(uint32_t flags) : mFlags(flags), mDataSource(new LiveDataSource), mHTTPDataSource( - new NuHTTPDataSource( + HTTPBase::Create( (mFlags & kFlagIncognito) - ? NuHTTPDataSource::kFlagIncognito + ? HTTPBase::kFlagIncognito : 0)), mPrevBandwidthIndex(-1), mLastPlaylistFetchTimeUs(-1), @@ -625,7 +625,12 @@ status_t LiveSession::decryptBuffer( } else { key = new ABuffer(16); - sp<NuHTTPDataSource> keySource = new NuHTTPDataSource; + sp<HTTPBase> keySource = + HTTPBase::Create( + (mFlags & kFlagIncognito) + ? HTTPBase::kFlagIncognito + : 0); + status_t err = keySource->connect(keyURI.c_str()); if (err == OK) { diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 4e6f75c..a9b7ae8 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -18,7 +18,7 @@ #define AWESOME_PLAYER_H_ -#include "NuHTTPDataSource.h" +#include "HTTPBase.h" #include "TimedEventQueue.h" #include <media/MediaPlayerInterface.h> @@ -93,7 +93,7 @@ struct AwesomePlayer { // This is a mask of MediaExtractor::Flags. uint32_t flags() const; - void postAudioEOS(); + void postAudioEOS(int64_t delayUs = 0ll); void postAudioSeekComplete(); private: @@ -203,13 +203,13 @@ private: void postVideoEvent_l(int64_t delayUs = -1); void postBufferingEvent_l(); void postStreamDoneEvent_l(status_t status); - void postCheckAudioStatusEvent_l(); + void postCheckAudioStatusEvent_l(int64_t delayUs); void postVideoLagEvent_l(); status_t play_l(); MediaBuffer *mVideoBuffer; - sp<NuHTTPDataSource> mConnectingDataSource; + sp<HTTPBase> mConnectingDataSource; sp<NuCachedSource2> mCachedSource; sp<ALooper> mLooper; @@ -217,7 +217,7 @@ private: sp<ARTSPController> mConnectingRTSPController; DrmManagerClient *mDrmManagerClient; - DecryptHandle *mDecryptHandle; + sp<DecryptHandle> mDecryptHandle; status_t setDataSource_l( const char *uri, diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h new file mode 100644 index 0000000..af49059 --- /dev/null +++ b/media/libstagefright/include/ChromiumHTTPDataSource.h @@ -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. + */ + +#ifndef CHROME_HTTP_DATA_SOURCE_H_ + +#define CHROME_HTTP_DATA_SOURCE_H_ + +#include <media/stagefright/foundation/AString.h> +#include <utils/threads.h> + +#include "HTTPBase.h" + +namespace android { + +struct SfDelegate; + +struct ChromiumHTTPDataSource : public HTTPBase { + ChromiumHTTPDataSource(uint32_t flags = 0); + + virtual status_t connect( + const char *uri, + const KeyedVector<String8, String8> *headers = NULL, + off64_t offset = 0); + + virtual void disconnect(); + + virtual status_t initCheck() const; + + virtual ssize_t readAt(off64_t offset, void *data, size_t size); + virtual status_t getSize(off64_t *size); + virtual uint32_t flags(); + + virtual bool estimateBandwidth(int32_t *bandwidth_bps); + + virtual sp<DecryptHandle> DrmInitialization(); + + virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); + + virtual String8 getUri(); + +protected: + virtual ~ChromiumHTTPDataSource(); + +private: + friend struct SfDelegate; + + enum State { + DISCONNECTED, + CONNECTING, + CONNECTED, + READING, + DISCONNECTING + }; + + struct BandwidthEntry { + int64_t mDelayUs; + size_t mNumBytes; + }; + + const uint32_t mFlags; + + mutable Mutex mLock; + Condition mCondition; + + State mState; + + SfDelegate *mDelegate; + + AString mURI; + KeyedVector<String8, String8> mHeaders; + + off64_t mCurrentOffset; + + // Any connection error or the result of a read operation + // (for the lattter this is the number of bytes read, if successful). + ssize_t mIOResult; + + int64_t mContentSize; + + List<BandwidthEntry> mBandwidthHistory; + size_t mNumBandwidthHistoryItems; + int64_t mTotalTransferTimeUs; + size_t mTotalTransferBytes; + + sp<DecryptHandle> mDecryptHandle; + DrmManagerClient *mDrmManagerClient; + + void disconnect_l(); + + status_t connect_l( + const char *uri, + const KeyedVector<String8, String8> *headers, + off64_t offset); + + static void InitiateRead( + ChromiumHTTPDataSource *me, void *data, size_t size); + + void initiateRead(void *data, size_t size); + + void onConnectionEstablished(int64_t contentSize); + void onConnectionFailed(status_t err); + void onReadCompleted(ssize_t size); + void onDisconnectComplete(); + + void addBandwidthMeasurement_l(size_t numBytes, int64_t delayUs); + + void clearDRMState_l(); + + DISALLOW_EVIL_CONSTRUCTORS(ChromiumHTTPDataSource); +}; + +} // namespace android + +#endif // CHROME_HTTP_DATA_SOURCE_H_ diff --git a/media/libstagefright/include/DRMExtractor.h b/media/libstagefright/include/DRMExtractor.h index 9881cc1..b4e4afb 100644 --- a/media/libstagefright/include/DRMExtractor.h +++ b/media/libstagefright/include/DRMExtractor.h @@ -45,7 +45,7 @@ private: sp<DataSource> mDataSource; sp<MediaExtractor> mOriginalExtractor; - DecryptHandle* mDecryptHandle; + sp<DecryptHandle> mDecryptHandle; DrmManagerClient* mDrmManagerClient; DRMExtractor(const DRMExtractor &); diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h new file mode 100644 index 0000000..6cec390 --- /dev/null +++ b/media/libstagefright/include/HTTPBase.h @@ -0,0 +1,53 @@ +/* + * 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 HTTP_BASE_H_ + +#define HTTP_BASE_H_ + +#include <media/stagefright/foundation/ABase.h> +#include <media/stagefright/DataSource.h> + +namespace android { + +struct HTTPBase : public DataSource { + enum Flags { + // Don't log any URLs. + kFlagIncognito = 1 + }; + + HTTPBase(); + + virtual status_t connect( + const char *uri, + const KeyedVector<String8, String8> *headers = NULL, + off64_t offset = 0) = 0; + + virtual void disconnect() = 0; + + // Returns true if bandwidth could successfully be estimated, + // false otherwise. + virtual bool estimateBandwidth(int32_t *bandwidth_bps) = 0; + + static sp<HTTPBase> Create(uint32_t flags = 0); + +private: + DISALLOW_EVIL_CONSTRUCTORS(HTTPBase); +}; + +} // namespace android + +#endif // HTTP_BASE_H_ diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h index 3fe5d4e..2b5ea0e 100644 --- a/media/libstagefright/include/LiveSession.h +++ b/media/libstagefright/include/LiveSession.h @@ -26,7 +26,7 @@ struct ABuffer; struct DataSource; struct LiveDataSource; struct M3UParser; -struct NuHTTPDataSource; +struct HTTPBase; struct LiveSession : public AHandler { enum Flags { @@ -75,7 +75,7 @@ private: sp<LiveDataSource> mDataSource; - sp<NuHTTPDataSource> mHTTPDataSource; + sp<HTTPBase> mHTTPDataSource; AString mMasterURL; Vector<BandwidthItem> mBandwidthItems; diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h index 04e8a6a..d9ef208 100644 --- a/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/include/MPEG4Extractor.h @@ -57,7 +57,7 @@ private: }; sp<DataSource> mDataSource; - bool mHaveMetadata; + status_t mInitCheck; bool mHasVideo; Track *mFirstTrack, *mLastTrack; @@ -90,6 +90,10 @@ private: status_t parseTrackHeader(off64_t data_offset, off64_t data_size); + Track *findTrackByMimePrefix(const char *mimePrefix); + + status_t verifyIfStreamable(); + MPEG4Extractor(const MPEG4Extractor &); MPEG4Extractor &operator=(const MPEG4Extractor &); }; diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index 022804c..02d5817 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -37,8 +37,8 @@ struct NuCachedSource2 : public DataSource { virtual status_t getSize(off64_t *size); virtual uint32_t flags(); - virtual DecryptHandle* DrmInitialization(); - virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client); + virtual sp<DecryptHandle> DrmInitialization(); + virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); virtual String8 getUri(); //////////////////////////////////////////////////////////////////////////// diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h index 2569568..7dd5d59 100644 --- a/media/libstagefright/include/NuHTTPDataSource.h +++ b/media/libstagefright/include/NuHTTPDataSource.h @@ -18,28 +18,24 @@ #define NU_HTTP_DATA_SOURCE_H_ -#include <media/stagefright/DataSource.h> #include <utils/List.h> #include <utils/String8.h> #include <utils/threads.h> #include "HTTPStream.h" +#include "include/HTTPBase.h" namespace android { -struct NuHTTPDataSource : public DataSource { - enum Flags { - // Don't log any URLs. - kFlagIncognito = 1 - }; +struct NuHTTPDataSource : public HTTPBase { NuHTTPDataSource(uint32_t flags = 0); - status_t connect( + virtual status_t connect( const char *uri, const KeyedVector<String8, String8> *headers = NULL, off64_t offset = 0); - void disconnect(); + virtual void disconnect(); virtual status_t initCheck() const; @@ -49,10 +45,10 @@ struct NuHTTPDataSource : public DataSource { // Returns true if bandwidth could successfully be estimated, // false otherwise. - bool estimateBandwidth(int32_t *bandwidth_bps); + virtual bool estimateBandwidth(int32_t *bandwidth_bps); - virtual DecryptHandle* DrmInitialization(); - virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client); + virtual sp<DecryptHandle> DrmInitialization(); + virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); virtual String8 getUri(); protected: @@ -98,7 +94,7 @@ private: int64_t mTotalTransferTimeUs; size_t mTotalTransferBytes; - DecryptHandle *mDecryptHandle; + sp<DecryptHandle> mDecryptHandle; DrmManagerClient *mDrmManagerClient; status_t connect( diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h index 07b1ec8..b02ed0e 100644 --- a/media/libstagefright/include/StagefrightMetadataRetriever.h +++ b/media/libstagefright/include/StagefrightMetadataRetriever.h @@ -32,7 +32,10 @@ struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface { StagefrightMetadataRetriever(); virtual ~StagefrightMetadataRetriever(); - virtual status_t setDataSource(const char *url); + 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 VideoFrame *getFrameAtTime(int64_t timeUs, int option); diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index 733de92..b3e29b9 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -60,7 +60,10 @@ struct DataSourceReader : public mkvparser::IMkvReader { virtual int Length(long long* total, long long* available) { off64_t size; if (mSource->getSize(&size) != OK) { - return -1; + *total = -1; + *available = (long long)((1ull << 63) - 1); + + return 0; } if (total) { @@ -84,7 +87,7 @@ private: //////////////////////////////////////////////////////////////////////////////// struct BlockIterator { - BlockIterator(mkvparser::Segment *segment, unsigned long trackNum); + BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum); bool eos() const; @@ -96,11 +99,14 @@ struct BlockIterator { int64_t blockTimeUs() const; private: - mkvparser::Segment *mSegment; + MatroskaExtractor *mExtractor; unsigned long mTrackNum; - mkvparser::Cluster *mCluster; + const mkvparser::Cluster *mCluster; const mkvparser::BlockEntry *mBlockEntry; + long mBlockEntryIndex; + + void advance_l(); BlockIterator(const BlockIterator &); BlockIterator &operator=(const BlockIterator &); @@ -150,7 +156,7 @@ MatroskaSource::MatroskaSource( : mExtractor(extractor), mTrackIndex(index), mType(OTHER), - mBlockIter(mExtractor->mSegment, + mBlockIter(mExtractor.get(), mExtractor->mTracks.itemAt(index).mTrackNum), mNALSizeLen(0) { sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta; @@ -199,11 +205,12 @@ sp<MetaData> MatroskaSource::getFormat() { //////////////////////////////////////////////////////////////////////////////// BlockIterator::BlockIterator( - mkvparser::Segment *segment, unsigned long trackNum) - : mSegment(segment), + MatroskaExtractor *extractor, unsigned long trackNum) + : mExtractor(extractor), mTrackNum(trackNum), mCluster(NULL), - mBlockEntry(NULL) { + mBlockEntry(NULL), + mBlockEntryIndex(0) { reset(); } @@ -212,45 +219,97 @@ bool BlockIterator::eos() const { } void BlockIterator::advance() { - while (!eos()) { - if (mBlockEntry != NULL) { - mBlockEntry = mCluster->GetNext(mBlockEntry); - } else if (mCluster != NULL) { - mCluster = mSegment->GetNext(mCluster); + Mutex::Autolock autoLock(mExtractor->mLock); + advance_l(); +} + +void BlockIterator::advance_l() { + for (;;) { + long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry); + LOGV("GetEntry returned %ld", res); + + long long pos; + long len; + if (res < 0) { + // Need to parse this cluster some more + + CHECK_EQ(res, mkvparser::E_BUFFER_NOT_FULL); + + res = mCluster->Parse(pos, len); + LOGV("Parse returned %ld", res); + + if (res < 0) { + // I/O error + + LOGE("Cluster::Parse returned result %ld", res); - if (eos()) { + mCluster = NULL; break; } - mBlockEntry = mCluster->GetFirst(); + continue; + } else if (res == 0) { + // We're done with this cluster + + const mkvparser::Cluster *nextCluster; + res = mExtractor->mSegment->ParseNext( + mCluster, nextCluster, pos, len); + LOGV("ParseNext returned %ld", res); + + if (res > 0) { + // EOF + + mCluster = NULL; + break; + } + + CHECK_EQ(res, 0); + CHECK(nextCluster != NULL); + CHECK(!nextCluster->EOS()); + + mCluster = nextCluster; + + res = mCluster->Parse(pos, len); + LOGV("Parse (2) returned %ld", res); + CHECK_GE(res, 0); + + mBlockEntryIndex = 0; + continue; } - if (mBlockEntry != NULL - && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) { + CHECK(mBlockEntry != NULL); + CHECK(mBlockEntry->GetBlock() != NULL); + ++mBlockEntryIndex; + + if (mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) { break; } } } void BlockIterator::reset() { - mCluster = mSegment->GetFirst(); - mBlockEntry = mCluster->GetFirst(); + Mutex::Autolock autoLock(mExtractor->mLock); - while (!eos() && block()->GetTrackNumber() != mTrackNum) { - advance(); - } + mCluster = mExtractor->mSegment->GetFirst(); + mBlockEntryIndex = 0; + + do { + advance_l(); + } while (!eos() && block()->GetTrackNumber() != mTrackNum); } void BlockIterator::seek(int64_t seekTimeUs) { - mCluster = mSegment->FindCluster(seekTimeUs * 1000ll); - mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL; + Mutex::Autolock autoLock(mExtractor->mLock); + + mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll); + mBlockEntryIndex = 0; while (!eos() && block()->GetTrackNumber() != mTrackNum) { - advance(); + advance_l(); } while (!eos() && !mBlockEntry->GetBlock()->IsKey()) { - advance(); + advance_l(); } } @@ -291,16 +350,6 @@ void MatroskaSource::clearPendingFrames() { } } -#define BAIL(err) \ - do { \ - if (bigbuf) { \ - bigbuf->release(); \ - bigbuf = NULL; \ - } \ - \ - return err; \ - } while (0) - status_t MatroskaSource::readBlock() { CHECK(mPendingFrames.empty()); @@ -310,181 +359,39 @@ status_t MatroskaSource::readBlock() { const mkvparser::Block *block = mBlockIter.block(); - size_t size = block->GetSize(); int64_t timeUs = mBlockIter.blockTimeUs(); - int32_t isSync = block->IsKey(); - - MediaBuffer *bigbuf = new MediaBuffer(size); - - long res = block->Read( - mExtractor->mReader, (unsigned char *)bigbuf->data()); - - if (res != 0) { - bigbuf->release(); - bigbuf = NULL; - - return ERROR_END_OF_STREAM; - } - - mBlockIter.advance(); - - bigbuf->meta_data()->setInt64(kKeyTime, timeUs); - bigbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync); - - unsigned lacing = (block->Flags() >> 1) & 3; - - if (lacing == 0) { - mPendingFrames.push_back(bigbuf); - return OK; - } - - LOGV("lacing = %u, size = %d", lacing, size); - - const uint8_t *data = (const uint8_t *)bigbuf->data(); - // hexdump(data, size); - - if (size == 0) { - BAIL(ERROR_MALFORMED); - } - - unsigned numFrames = (unsigned)data[0] + 1; - ++data; - --size; - - Vector<uint64_t> frameSizes; - - switch (lacing) { - case 1: // Xiph - { - for (size_t i = 0; i < numFrames - 1; ++i) { - size_t frameSize = 0; - uint8_t byte; - do { - if (size == 0) { - BAIL(ERROR_MALFORMED); - } - byte = data[0]; - ++data; - --size; - - frameSize += byte; - } while (byte == 0xff); - - frameSizes.push(frameSize); - } - - break; - } - - case 2: // fixed-size - { - if ((size % numFrames) != 0) { - BAIL(ERROR_MALFORMED); - } - - size_t frameSize = size / numFrames; - for (size_t i = 0; i < numFrames - 1; ++i) { - frameSizes.push(frameSize); - } - - break; - } - - case 3: // EBML - { - uint64_t lastFrameSize = 0; - for (size_t i = 0; i < numFrames - 1; ++i) { - uint8_t byte; - if (size == 0) { - BAIL(ERROR_MALFORMED); - } - byte = data[0]; - ++data; - --size; - - size_t numLeadingZeroes = clz(byte); - - uint64_t frameSize = byte & ~(0x80 >> numLeadingZeroes); - for (size_t j = 0; j < numLeadingZeroes; ++j) { - if (size == 0) { - BAIL(ERROR_MALFORMED); - } - - frameSize = frameSize << 8; - frameSize |= data[0]; - ++data; - --size; - } - - if (i == 0) { - frameSizes.push(frameSize); - } else { - size_t shift = - 7 - numLeadingZeroes + 8 * numLeadingZeroes; - - int64_t delta = - (int64_t)frameSize - (1ll << (shift - 1)) + 1; - - frameSize = lastFrameSize + delta; - - frameSizes.push(frameSize); - } - - lastFrameSize = frameSize; - } - break; - } + for (int i = 0; i < block->GetFrameCount(); ++i) { + const mkvparser::Block::Frame &frame = block->GetFrame(i); - default: - TRESPASS(); - } - -#if 0 - AString out; - for (size_t i = 0; i < frameSizes.size(); ++i) { - if (i > 0) { - out.append(", "); - } - out.append(StringPrintf("%llu", frameSizes.itemAt(i))); - } - LOGV("sizes = [%s]", out.c_str()); -#endif + MediaBuffer *mbuf = new MediaBuffer(frame.len); + mbuf->meta_data()->setInt64(kKeyTime, timeUs); + mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey()); - for (size_t i = 0; i < frameSizes.size(); ++i) { - uint64_t frameSize = frameSizes.itemAt(i); + long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data()); + if (n != 0) { + mPendingFrames.clear(); - if (size < frameSize) { - BAIL(ERROR_MALFORMED); + mBlockIter.advance(); + return ERROR_IO; } - MediaBuffer *mbuf = new MediaBuffer(frameSize); - mbuf->meta_data()->setInt64(kKeyTime, timeUs); - mbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync); - memcpy(mbuf->data(), data, frameSize); mPendingFrames.push_back(mbuf); - - data += frameSize; - size -= frameSize; } - size_t offset = bigbuf->range_length() - size; - bigbuf->set_range(offset, size); - - mPendingFrames.push_back(bigbuf); + mBlockIter.advance(); return OK; } -#undef BAIL - status_t MatroskaSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; int64_t seekTimeUs; ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { + if (options && options->getSeekTo(&seekTimeUs, &mode) + && !mExtractor->isLiveStreaming()) { clearPendingFrames(); mBlockIter.seek(seekTimeUs); } @@ -584,6 +491,13 @@ MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) mReader(new DataSourceReader(mDataSource)), mSegment(NULL), mExtractedThumbnails(false) { + off64_t size; + mIsLiveStreaming = + (mDataSource->flags() + & (DataSource::kWantsPrefetching + | DataSource::kIsCachingDataSource)) + && mDataSource->getSize(&size) != OK; + mkvparser::EBMLHeader ebmlHeader; long long pos; if (ebmlHeader.Parse(mReader, pos) < 0) { @@ -598,7 +512,16 @@ MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) return; } - ret = mSegment->Load(); + if (isLiveStreaming()) { + ret = mSegment->ParseHeaders(); + CHECK_EQ(ret, 0); + + long len; + ret = mSegment->LoadCluster(pos, len); + CHECK_EQ(ret, 0); + } else { + ret = mSegment->Load(); + } if (ret < 0) { delete mSegment; @@ -635,7 +558,8 @@ sp<MetaData> MatroskaExtractor::getTrackMetaData( return NULL; } - if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) { + if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails + && !isLiveStreaming()) { findThumbnails(); mExtractedThumbnails = true; } @@ -643,6 +567,10 @@ sp<MetaData> MatroskaExtractor::getTrackMetaData( return mTracks.itemAt(index).mMeta; } +bool MatroskaExtractor::isLiveStreaming() const { + return mIsLiveStreaming; +} + static void addESDSFromAudioSpecificInfo( const sp<MetaData> &meta, const void *asi, size_t asiSize) { static const uint8_t kStaticESDS[] = { @@ -794,7 +722,7 @@ void MatroskaExtractor::findThumbnails() { continue; } - BlockIterator iter(mSegment, info->mTrackNum); + BlockIterator iter(this, info->mTrackNum); int32_t i = 0; int64_t thumbnailTimeUs = 0; size_t maxBlockSize = 0; @@ -802,7 +730,11 @@ void MatroskaExtractor::findThumbnails() { if (iter.block()->IsKey()) { ++i; - size_t blockSize = iter.block()->GetSize(); + size_t blockSize = 0; + for (int i = 0; i < iter.block()->GetFrameCount(); ++i) { + blockSize += iter.block()->GetFrame(i).len; + } + if (blockSize > maxBlockSize) { maxBlockSize = blockSize; thumbnailTimeUs = iter.blockTimeUs(); @@ -821,6 +753,15 @@ sp<MetaData> MatroskaExtractor::getMetaData() { return meta; } +uint32_t MatroskaExtractor::flags() const { + uint32_t x = CAN_PAUSE; + if (!isLiveStreaming()) { + x |= CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK; + } + + return x; +} + bool SniffMatroska( const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *) { diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h index fa20b84..38ebd61 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.h +++ b/media/libstagefright/matroska/MatroskaExtractor.h @@ -20,6 +20,7 @@ #include <media/stagefright/MediaExtractor.h> #include <utils/Vector.h> +#include <utils/threads.h> namespace mkvparser { struct Segment; @@ -45,26 +46,34 @@ struct MatroskaExtractor : public MediaExtractor { virtual sp<MetaData> getMetaData(); + virtual uint32_t flags() const; + protected: virtual ~MatroskaExtractor(); private: friend struct MatroskaSource; + friend struct BlockIterator; struct TrackInfo { unsigned long mTrackNum; sp<MetaData> mMeta; }; + + Mutex mLock; Vector<TrackInfo> mTracks; sp<DataSource> mDataSource; DataSourceReader *mReader; mkvparser::Segment *mSegment; bool mExtractedThumbnails; + bool mIsLiveStreaming; void addTracks(); void findThumbnails(); + bool isLiveStreaming() const; + MatroskaExtractor(const MatroskaExtractor &); MatroskaExtractor &operator=(const MatroskaExtractor &); }; diff --git a/media/libstagefright/yuv/Android.mk b/media/libstagefright/yuv/Android.mk index 7697e3c..a4253f6 100644 --- a/media/libstagefright/yuv/Android.mk +++ b/media/libstagefright/yuv/Android.mk @@ -10,6 +10,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE:= libstagefright_yuv -LOCAL_PRELINK_MODULE := false + include $(BUILD_SHARED_LIBRARY) diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java index 34025f6..90be041 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java @@ -744,7 +744,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media assertNotNull(msg + ": could not create AudioEffect", effect); byte[] param = intToByteArray(Equalizer.PARAM_CURRENT_PRESET); byte[] value = new byte[2]; - if (effect.getParameter(param, value) == AudioEffect.SUCCESS) { + if (!AudioEffect.isError(effect.getParameter(param, value))) { result = true; } } catch (IllegalArgumentException e) { @@ -777,8 +777,8 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media 0); assertNotNull(msg + ": could not create AudioEffect", effect); int[] value = new int[1]; - if (effect.getParameter(EnvironmentalReverb.PARAM_DECAY_TIME, value) - == AudioEffect.SUCCESS) { + if (!AudioEffect.isError( + effect.getParameter(EnvironmentalReverb.PARAM_DECAY_TIME, value))) { result = true; } } catch (IllegalArgumentException e) { @@ -811,8 +811,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media 0); assertNotNull(msg + ": could not create AudioEffect", effect); short[] value = new short[1]; - if (effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value) - == AudioEffect.SUCCESS) { + if (!AudioEffect.isError(effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value))) { result = true; } } catch (IllegalArgumentException e) { @@ -845,8 +844,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media 0); assertNotNull(msg + ": could not create AudioEffect", effect); byte[] value = new byte[2]; - if (effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value) - == AudioEffect.SUCCESS) { + if (!AudioEffect.isError(effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value))) { result = true; } } catch (IllegalArgumentException e) { @@ -881,8 +879,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media int[] param = new int[1]; int[] value = new int[1]; param[0] = EnvironmentalReverb.PARAM_DECAY_TIME; - if (effect.getParameter(param, value) - == AudioEffect.SUCCESS) { + if (!AudioEffect.isError(effect.getParameter(param, value))) { result = true; } } catch (IllegalArgumentException e) { @@ -917,8 +914,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media int[] param = new int[1]; short[] value = new short[1]; param[0] = Equalizer.PARAM_CURRENT_PRESET; - if (effect.getParameter(param, value) - == AudioEffect.SUCCESS) { + if (!AudioEffect.isError(effect.getParameter(param, value))) { result = true; } } catch (IllegalArgumentException e) { @@ -953,8 +949,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media int[] param = new int[1]; byte[] value = new byte[2]; param[0] = Equalizer.PARAM_CURRENT_PRESET; - if (effect.getParameter(param, value) - == AudioEffect.SUCCESS) { + if (!AudioEffect.isError(effect.getParameter(param, value))) { result = true; } } catch (IllegalArgumentException e) { @@ -1082,8 +1077,8 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media short[] value = new short[1]; status = effect2.getParameter(Equalizer.PARAM_CURRENT_PRESET, value); - assertEquals(msg + ": Effect2 getParameter failed", - AudioEffect.SUCCESS, status); + assertFalse(msg + ": Effect2 getParameter failed", + AudioEffect.isError(status)); assertEquals(msg + ": Effect1 changed parameter", (short)0, value[0]); @@ -1278,7 +1273,7 @@ public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<Media byte[] cmd = new byte[0]; byte[] reply = new byte[4]; int status = effect.command(3, cmd, reply); - assertEquals(msg + ": command failed", AudioEffect.SUCCESS, status); + assertFalse(msg + ": command failed", AudioEffect.isError(status)); assertTrue(msg + ": effect not enabled", effect.getEnabled()); result = true; } catch (IllegalStateException e) { diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk index 10367cf..c655ae6 100644 --- a/media/tests/players/Android.mk +++ b/media/tests/players/Android.mk @@ -24,6 +24,6 @@ LOCAL_SHARED_LIBRARIES:= \ LOCAL_MODULE:= invoke_mock_media_player LOCAL_MODULE_TAGS := tests eng -LOCAL_PRELINK_MODULE:= false + include $(BUILD_SHARED_LIBRARY) diff --git a/native/android/Android.mk b/native/android/Android.mk index 44ec83f..9940442 100644 --- a/native/android/Android.mk +++ b/native/android/Android.mk @@ -22,7 +22,6 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libui \ libgui \ - libsurfaceflinger_client \ libandroid_runtime LOCAL_STATIC_LIBRARIES := \ diff --git a/native/include/android/input.h b/native/include/android/input.h index 86be54a..f1738c6 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -297,6 +297,14 @@ enum { * may not be the window currently touched. */ AMOTION_EVENT_ACTION_SCROLL = 8, + + /* The pointer is not down but has entered the boundaries of a window or view. + */ + AMOTION_EVENT_ACTION_HOVER_ENTER = 9, + + /* The pointer is not down but has exited the boundaries of a window or view. + */ + AMOTION_EVENT_ACTION_HOVER_EXIT = 10, }; /* @@ -657,7 +665,8 @@ int64_t AMotionEvent_getHistoricalEventTime(AInputEvent* motion_event, * and views. * Whole numbers are pixels; the value may have a fraction for input devices * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index); +float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); /* Get the historical raw Y coordinate of this event for the given pointer index that * occurred between this event and the previous motion event. @@ -666,7 +675,8 @@ float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t poi * and views. * Whole numbers are pixels; the value may have a fraction for input devices * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index); +float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index, + size_t history_index); /* Get the historical X coordinate of this event for the given pointer index that * occurred between this event and the previous motion event. diff --git a/native/include/android/keycodes.h b/native/include/android/keycodes.h index c4a7eff..5d49775 100644 --- a/native/include/android/keycodes.h +++ b/native/include/android/keycodes.h @@ -247,6 +247,9 @@ enum { AKEYCODE_BUTTON_14 = 201, AKEYCODE_BUTTON_15 = 202, AKEYCODE_BUTTON_16 = 203, + AKEYCODE_LANGUAGE_SWITCH = 204, + AKEYCODE_MANNER_MODE = 205, + AKEYCODE_3D_MODE = 206, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/opengl/libagl2/Android.mk b/opengl/libagl2/Android.mk new file mode 100644 index 0000000..564932f --- /dev/null +++ b/opengl/libagl2/Android.mk @@ -0,0 +1,58 @@ +LOCAL_PATH:= $(call my-dir) + +# +# Build the software OpenGL ES library +# + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + src/api.cpp \ + src/egl.cpp \ + src/get.cpp \ + src/shader.cpp \ + src/state.cpp \ + src/texture.cpp \ + src/vertex.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH) \ + external/mesa3d/include \ + external/mesa3d/src \ + external/stlport/stlport \ + bionic + +#LOCAL_CFLAGS += -DLOG_TAG=\"libagl2\" +#LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +#LOCAL_CFLAGS += -fvisibility=hidden +#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG +LOCAL_CFLAGS += -O3 +LOCAL_STATIC_LIBRARIES := libMesa +LOCAL_SHARED_LIBRARIES := libstlport libcutils libhardware libutils libbcc libdl +LOCAL_LDLIBS := -lpthread + +ifeq ($(TARGET_ARCH),arm) + LOCAL_CFLAGS += -fstrict-aliasing +endif + +ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true) + LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER +endif + +ifneq ($(TARGET_SIMULATOR),true) + # we need to access the private Bionic header <bionic_tls.h> + # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER + # behavior from the bionic Android.mk file + ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true) + LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER + endif + LOCAL_C_INCLUDES += bionic/libc/private +endif + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl +#replace libagl for now +LOCAL_MODULE:= libGLES_android +LOCAL_MODULE_TAGS := eng + +## Disable this makefile for now +## include $(BUILD_SHARED_LIBRARY) diff --git a/opengl/libagl2/README b/opengl/libagl2/README new file mode 100644 index 0000000..34746d3 --- /dev/null +++ b/opengl/libagl2/README @@ -0,0 +1,26 @@ +libAgl2 provides software GL ES 2.0 implementation using Pixelflinger2 in external/mesa3d + +To build, enable Android.mk, which builds libGLES_android.so, then replace the one built from libAgl in system/lib/egl. +ES 1.0 functions are not implemented and will cause exit, so do not setprop debug.egl.hw 0 until launcher is loaded. + +All functions have little to none error checking. +Not thread safe, Pixelflinger2 uses some static data. + +Most shader functions are implemented, however, most Get* functions for shaders/programs/uniforms/attribs are not. +No name system for shaders/programs, just using the pointers as names. + +Basic glTexImage2D, glTexSubImage2D, glCopyImage2D and glCopySubImage2D are implemented, with a range of 8/16/24/32bpp formats. +Cube map support is minimal. No mipmapping. +TexParameter is mostly implemented, supports texcoord wrap modes, and only linear for both min and mag, or nearest for both min and mag filtering. +Texture names are implemented, but bad. + +Frame buffer and render buffers are not implemented. + +Depth and stencil are implemented, but not tested. +Blending seems to work. +Colorbuffer supports RGBA_8888 and RGB_565. + +Vertex buffer objects are implemented. +Some GL_TRIANGLES and GL_TRIANGLE_STRIPS modes for glDrawArrays and glDrawElements are implemented, but vertex order is probably wrong so culling is disabled. + +Basic apps should work, and some libhwui should work, except for frame buffer operations, which will cause exit. diff --git a/opengl/libagl2/libagl2.project b/opengl/libagl2/libagl2.project new file mode 100644 index 0000000..f234421 --- /dev/null +++ b/opengl/libagl2/libagl2.project @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?> +<CodeLite_Project Name="libagl2" InternalType="Console"> + <Plugins> + <Plugin Name="qmake"> + <![CDATA[00010001N0005Debug000000000000]]> + </Plugin> + </Plugins> + <Description/> + <Dependencies/> + <Dependencies Name="Release"/> + <VirtualDirectory Name="src"> + <File Name="src/egl.cpp"/> + <File Name="src/api.cpp"/> + <File Name="src/gles2context.h"/> + <File Name="src/shader.cpp"/> + <File Name="src/vertex.cpp"/> + <File Name="src/state.cpp"/> + <File Name="src/texture.cpp"/> + <File Name="src/get.cpp"/> + </VirtualDirectory> + <VirtualDirectory Name="include"/> + <Settings Type="Executable"> + <Configuration Name="Debug" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append"> + <Compiler Options="-g;-m32" Required="yes" PreCompiledHeader=""> + <IncludePath Value="/usr/include/c++/4.4"/> + <IncludePath Value="/usr/include/c++/4.4/ext"/> + <IncludePath Value="."/> + <IncludePath Value="include"/> + <IncludePath Value="../../../../external/mesa3d/include"/> + <IncludePath Value="../../../../external/mesa3d/src"/> + <IncludePath Value="../../../../hardware/libhardware/include"/> + <IncludePath Value="../../../../system/core/include"/> + <IncludePath Value="../include"/> + <IncludePath Value="../../include"/> + <IncludePath Value="../../../../development/ndk/platforms/android-9/include"/> + <IncludePath Value="../../../../bionic/libc/include/"/> + <IncludePath Value="/../../../../development/ndk/platforms/android-5/arch-x86/include"/> + <IncludePath Value="../../../../bionic/libc/arch-x86/include"/> + <IncludePath Value="../../../../bionic/libc/kernel/arch-x86"/> + <IncludePath Value="/../../../../external/kernel-headers/original"/> + <IncludePath Value="../../../../prebuilt/ndk/android-ndk-r4/platforms/android-8/arch-x86/usr/include"/> + </Compiler> + <Linker Options="-m32;-lstdc++" Required="yes"/> + <ResourceCompiler Options="" Required="no"/> + <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Debug" Command="./$(ProjectName)" CommandArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/> + <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath=""> + <PostConnectCommands/> + <StartupCommands/> + </Debugger> + <PreBuild/> + <PostBuild/> + <CustomBuild Enabled="no"> + <RebuildCommand/> + <CleanCommand/> + <BuildCommand/> + <PreprocessFileCommand/> + <SingleFileCommand/> + <MakefileGenerationCommand/> + <ThirdPartyToolName>None</ThirdPartyToolName> + <WorkingDirectory/> + </CustomBuild> + <AdditionalRules> + <CustomPostBuild/> + <CustomPreBuild/> + </AdditionalRules> + </Configuration> + <Configuration Name="Release" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append"> + <Compiler Options="" Required="yes" PreCompiledHeader=""> + <IncludePath Value="."/> + </Compiler> + <Linker Options="-O2" Required="yes"/> + <ResourceCompiler Options="" Required="no"/> + <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Release" Command="./$(ProjectName)" CommandArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/> + <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath=""> + <PostConnectCommands/> + <StartupCommands/> + </Debugger> + <PreBuild/> + <PostBuild/> + <CustomBuild Enabled="no"> + <RebuildCommand/> + <CleanCommand/> + <BuildCommand/> + <PreprocessFileCommand/> + <SingleFileCommand/> + <MakefileGenerationCommand/> + <ThirdPartyToolName>None</ThirdPartyToolName> + <WorkingDirectory/> + </CustomBuild> + <AdditionalRules> + <CustomPostBuild/> + <CustomPreBuild/> + </AdditionalRules> + </Configuration> + <GlobalSettings> + <Compiler Options=""> + <IncludePath Value="."/> + </Compiler> + <Linker Options=""> + <LibraryPath Value="."/> + </Linker> + <ResourceCompiler Options=""/> + </GlobalSettings> + </Settings> + <Dependencies Name="Debug"> + <Project Name="libMesa"/> + </Dependencies> +</CodeLite_Project> diff --git a/opengl/libagl2/src/api.cpp b/opengl/libagl2/src/api.cpp new file mode 100644 index 0000000..bb8d62b --- /dev/null +++ b/opengl/libagl2/src/api.cpp @@ -0,0 +1,266 @@ +#include "gles2context.h" + +#define API_ENTRY +#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0); +#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0; + + +void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) +{ + CALL_GL_API(glBindFramebuffer, target, framebuffer); +} +void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) +{ + CALL_GL_API(glBindRenderbuffer, target, renderbuffer); +} +GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) +{ + CALL_GL_API_RETURN(glCheckFramebufferStatus, target); +} +void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + CALL_GL_API(glColorMask, red, green, blue, alpha); +} +void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers) +{ + CALL_GL_API(glDeleteFramebuffers, n, framebuffers); +} +void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers) +{ + CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers); +} +void API_ENTRY(glDepthFunc)(GLenum func) +{ + CALL_GL_API(glDepthFunc, func); +} +void API_ENTRY(glDepthMask)(GLboolean flag) +{ + CALL_GL_API(glDepthMask, flag); +} +void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) +{ + CALL_GL_API(glDepthRangef, zNear, zFar); +} +void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ + CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer); +} +void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ + CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level); +} +void glGenerateMipmap(GLenum target) +{ + //CALL_GL_API(glGenerateMipmap, target); + LOGD("agl2: glGenerateMipmap not implemented"); +} +void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint* framebuffers) +{ + CALL_GL_API(glGenFramebuffers, n, framebuffers); +} +void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers) +{ + CALL_GL_API(glGenRenderbuffers, n, renderbuffers); +} +void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +{ + CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name); +} +void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +{ + CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name); +} +void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ + CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders); +} +void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) +{ + CALL_GL_API(glGetBooleanv, pname, params); +} +void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) +{ + CALL_GL_API(glGetBufferParameteriv, target, pname, params); +} +GLenum glGetError(void) +{ + puts("agl2: glGetError"); + return GL_NO_ERROR; + //CALL_GL_API_RETURN(glGetError); +} +void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params) +{ + CALL_GL_API(glGetFloatv, pname, params); +} +void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) +{ + CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params); +} +void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) +{ + CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params); +} +void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ + CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision); +} +void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +{ + CALL_GL_API(glGetShaderSource, shader, bufsize, length, source); +} +void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params) +{ + CALL_GL_API(glGetUniformfv, program, location, params); +} +void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) +{ + CALL_GL_API(glGetUniformiv, program, location, params); +} +void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) +{ + CALL_GL_API(glGetVertexAttribfv, index, pname, params); +} +void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) +{ + CALL_GL_API(glGetVertexAttribiv, index, pname, params); +} +void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer) +{ + CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer); +} +GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) +{ + CALL_GL_API_RETURN(glIsBuffer, buffer); +} +GLboolean API_ENTRY(glIsEnabled)(GLenum cap) +{ + CALL_GL_API_RETURN(glIsEnabled, cap); +} +GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) +{ + CALL_GL_API_RETURN(glIsFramebuffer, framebuffer); +} +GLboolean API_ENTRY(glIsProgram)(GLuint program) +{ + CALL_GL_API_RETURN(glIsProgram, program); +} +GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) +{ + CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer); +} +GLboolean API_ENTRY(glIsShader)(GLuint shader) +{ + CALL_GL_API_RETURN(glIsShader, shader); +} +void API_ENTRY(glLineWidth)(GLfloat width) +{ + CALL_GL_API(glLineWidth, width); +} +void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) +{ + CALL_GL_API(glPolygonOffset, factor, units); +} +void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) +{ + CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels); +} +void API_ENTRY(glReleaseShaderCompiler)(void) +{ + CALL_GL_API(glReleaseShaderCompiler); +} +void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height); +} +void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) +{ + CALL_GL_API(glSampleCoverage, value, invert); +} +void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +{ + CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length); +} +void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) +{ + CALL_GL_API(glStencilFunc, func, ref, mask); +} +void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask); +} +void API_ENTRY(glStencilMask)(GLuint mask) +{ + CALL_GL_API(glStencilMask, mask); +} +void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) +{ + CALL_GL_API(glStencilMaskSeparate, face, mask); +} +void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) +{ + CALL_GL_API(glStencilOp, fail, zfail, zpass); +} +void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass); +} +void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat* v) +{ + CALL_GL_API(glUniform1fv, location, count, v); +} +void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint* v) +{ + CALL_GL_API(glUniform1iv, location, count, v); +} +void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat* v) +{ + CALL_GL_API(glUniform2fv, location, count, v); +} +void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y) +{ + CALL_GL_API(glUniform2i, location, x, y); +} +void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint* v) +{ + CALL_GL_API(glUniform2iv, location, count, v); +} +void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + CALL_GL_API(glUniform3f, location, x, y, z); +} +void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat* v) +{ + CALL_GL_API(glUniform3fv, location, count, v); +} +void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z) +{ + CALL_GL_API(glUniform3i, location, x, y, z); +} +void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint* v) +{ + CALL_GL_API(glUniform3iv, location, count, v); +} +void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat* v) +{ + CALL_GL_API(glUniform4fv, location, count, v); +} +void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + CALL_GL_API(glUniform4i, location, x, y, z, w); +} +void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint* v) +{ + CALL_GL_API(glUniform4iv, location, count, v); +} +void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value); +} +void API_ENTRY(glValidateProgram)(GLuint program) +{ + CALL_GL_API(glValidateProgram, program); +} diff --git a/opengl/libagl2/src/egl.cpp b/opengl/libagl2/src/egl.cpp new file mode 100644 index 0000000..6184644 --- /dev/null +++ b/opengl/libagl2/src/egl.cpp @@ -0,0 +1,2232 @@ +/* +** +** Copyright 2007 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 <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> + +#include <cutils/atomic.h> + + +#include <private/ui/android_natives_priv.h> + +#include <hardware/copybit.h> + +#include "gles2context.h" + +// ---------------------------------------------------------------------------- +namespace android +{ +// ---------------------------------------------------------------------------- + +const unsigned int NUM_DISPLAYS = 1; + +static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t gEGLErrorKey = -1; +#ifndef HAVE_ANDROID_OS +namespace gl { +pthread_key_t gGLKey = -1; +}; // namespace gl +#endif + +template<typename T> +static T setError(GLint error, T returnValue) +{ + if (ggl_unlikely(gEGLErrorKey == -1)) { + pthread_mutex_lock(&gErrorKeyMutex); + if (gEGLErrorKey == -1) + pthread_key_create(&gEGLErrorKey, NULL); + pthread_mutex_unlock(&gErrorKeyMutex); + } + pthread_setspecific(gEGLErrorKey, (void*)error); + return returnValue; +} + +static GLint getError() +{ + if (ggl_unlikely(gEGLErrorKey == -1)) + return EGL_SUCCESS; + GLint error = (GLint)pthread_getspecific(gEGLErrorKey); + if (error == 0) { + // The TLS key has been created by another thread, but the value for + // this thread has not been initialized. + return EGL_SUCCESS; + } + pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS); + return error; +} + +// ---------------------------------------------------------------------------- + +struct egl_display_t { + egl_display_t() : type(0), initialized(0) { } + + static egl_display_t& get_display(EGLDisplay dpy); + + static EGLBoolean is_valid(EGLDisplay dpy) { + return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE; + } + + NativeDisplayType type; + volatile int32_t initialized; +}; + +static egl_display_t gDisplays[NUM_DISPLAYS]; + +egl_display_t& egl_display_t::get_display(EGLDisplay dpy) +{ + return gDisplays[uintptr_t(dpy)-1U]; +} + +// ---------------------------------------------------------------------------- + +struct egl_surface_t { + enum { + PAGE_FLIP = 0x00000001, + MAGIC = 0x31415265 + }; + + uint32_t magic; + EGLDisplay dpy; + EGLConfig config; + EGLContext ctx; + + egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat); + virtual ~egl_surface_t(); + bool isValid() const; + virtual bool initCheck() const = 0; + + virtual EGLBoolean bindDrawSurface(GLES2Context* gl) = 0; + virtual EGLBoolean bindReadSurface(GLES2Context* gl) = 0; + virtual EGLBoolean connect() { + return EGL_TRUE; + } + virtual void disconnect() {} + virtual EGLint getWidth() const = 0; + virtual EGLint getHeight() const = 0; + + virtual EGLint getHorizontalResolution() const; + virtual EGLint getVerticalResolution() const; + virtual EGLint getRefreshRate() const; + virtual EGLint getSwapBehavior() const; + virtual EGLBoolean swapBuffers(); + virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); +protected: + GGLSurface depth; +}; + +egl_surface_t::egl_surface_t(EGLDisplay dpy, + EGLConfig config, + int32_t depthFormat) + : magic(MAGIC), dpy(dpy), config(config), ctx(0) +{ + depth.version = sizeof(GGLSurface); + depth.data = 0; + depth.format = (GGLPixelFormat)depthFormat; +} +egl_surface_t::~egl_surface_t() +{ + magic = 0; + free(depth.data); +} +bool egl_surface_t::isValid() const +{ + LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this); + return magic == MAGIC; +} + +EGLBoolean egl_surface_t::swapBuffers() +{ + return EGL_FALSE; +} +EGLint egl_surface_t::getHorizontalResolution() const +{ + return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); +} +EGLint egl_surface_t::getVerticalResolution() const +{ + return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); +} +EGLint egl_surface_t::getRefreshRate() const +{ + return (60 * EGL_DISPLAY_SCALING); +} +EGLint egl_surface_t::getSwapBehavior() const +{ + return EGL_BUFFER_PRESERVED; +} +EGLBoolean egl_surface_t::setSwapRectangle( + EGLint l, EGLint t, EGLint w, EGLint h) +{ + return EGL_FALSE; +} + +// ---------------------------------------------------------------------------- + +struct egl_window_surface_v2_t : public egl_surface_t { + egl_window_surface_v2_t( + EGLDisplay dpy, EGLConfig config, + int32_t depthFormat, + ANativeWindow* window); + + ~egl_window_surface_v2_t(); + + virtual bool initCheck() const { + return true; // TODO: report failure if ctor fails + } + virtual EGLBoolean swapBuffers(); + virtual EGLBoolean bindDrawSurface(GLES2Context* gl); + virtual EGLBoolean bindReadSurface(GLES2Context* gl); + virtual EGLBoolean connect(); + virtual void disconnect(); + virtual EGLint getWidth() const { + return width; + } + virtual EGLint getHeight() const { + return height; + } + virtual EGLint getHorizontalResolution() const; + virtual EGLint getVerticalResolution() const; + virtual EGLint getRefreshRate() const; + virtual EGLint getSwapBehavior() const; + virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); + +private: + status_t lock(android_native_buffer_t* buf, int usage, void** vaddr); + status_t unlock(android_native_buffer_t* buf); + ANativeWindow* nativeWindow; + android_native_buffer_t* buffer; + android_native_buffer_t* previousBuffer; + gralloc_module_t const* module; + copybit_device_t* blitengine; + int width; + int height; + void* bits; + GGLFormat const* pixelFormatTable; + + struct Rect { + inline Rect() { }; + inline Rect(int32_t w, int32_t h) + : left(0), top(0), right(w), bottom(h) { } + inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) + : left(l), top(t), right(r), bottom(b) { } + Rect& andSelf(const Rect& r) { + left = max(left, r.left); + top = max(top, r.top); + right = min(right, r.right); + bottom = min(bottom, r.bottom); + return *this; + } + bool isEmpty() const { + return (left>=right || top>=bottom); + } + void dump(char const* what) { + LOGD("%s { %5d, %5d, w=%5d, h=%5d }", + what, left, top, right-left, bottom-top); + } + + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; + }; + + struct Region { + inline Region() : count(0) { } + typedef Rect const* const_iterator; + const_iterator begin() const { + return storage; + } + const_iterator end() const { + return storage+count; + } + static Region subtract(const Rect& lhs, const Rect& rhs) { + Region reg; + Rect* storage = reg.storage; + if (!lhs.isEmpty()) { + if (lhs.top < rhs.top) { // top rect + storage->left = lhs.left; + storage->top = lhs.top; + storage->right = lhs.right; + storage->bottom = rhs.top; + storage++; + } + const int32_t top = max(lhs.top, rhs.top); + const int32_t bot = min(lhs.bottom, rhs.bottom); + if (top < bot) { + if (lhs.left < rhs.left) { // left-side rect + storage->left = lhs.left; + storage->top = top; + storage->right = rhs.left; + storage->bottom = bot; + storage++; + } + if (lhs.right > rhs.right) { // right-side rect + storage->left = rhs.right; + storage->top = top; + storage->right = lhs.right; + storage->bottom = bot; + storage++; + } + } + if (lhs.bottom > rhs.bottom) { // bottom rect + storage->left = lhs.left; + storage->top = rhs.bottom; + storage->right = lhs.right; + storage->bottom = lhs.bottom; + storage++; + } + reg.count = storage - reg.storage; + } + return reg; + } + bool isEmpty() const { + return count<=0; + } +private: + Rect storage[4]; + ssize_t count; + }; + + struct region_iterator : public copybit_region_t { + region_iterator(const Region& region) + : b(region.begin()), e(region.end()) { + this->next = iterate; + } +private: + static int iterate(copybit_region_t const * self, copybit_rect_t* rect) { + region_iterator const* me = static_cast<region_iterator const*>(self); + if (me->b != me->e) { + *reinterpret_cast<Rect*>(rect) = *me->b++; + return 1; + } + return 0; + } + mutable Region::const_iterator b; + Region::const_iterator const e; + }; + + void copyBlt( + android_native_buffer_t* dst, void* dst_vaddr, + android_native_buffer_t* src, void const* src_vaddr, + const Region& clip); + + Rect dirtyRegion; + Rect oldDirtyRegion; +}; + +egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy, + EGLConfig config, + int32_t depthFormat, + ANativeWindow* window) + : egl_surface_t(dpy, config, depthFormat), + nativeWindow(window), buffer(0), previousBuffer(0), module(0), + blitengine(0), bits(NULL) +{ + hw_module_t const* pModule; + hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule); + module = reinterpret_cast<gralloc_module_t const*>(pModule); + + if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) { + copybit_open(pModule, &blitengine); + } + + pixelFormatTable = gglGetPixelFormatTable(); + + // keep a reference on the window + nativeWindow->common.incRef(&nativeWindow->common); + nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width); + nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height); + int format = 0; + nativeWindow->query(nativeWindow, NATIVE_WINDOW_FORMAT, &format); + LOGD("agl2: egl_window_surface_v2_t format=0x%.4X", format); +// assert(0); +} + +egl_window_surface_v2_t::~egl_window_surface_v2_t() +{ + if (buffer) { + buffer->common.decRef(&buffer->common); + } + if (previousBuffer) { + previousBuffer->common.decRef(&previousBuffer->common); + } + nativeWindow->common.decRef(&nativeWindow->common); + if (blitengine) { + copybit_close(blitengine); + } +} + +EGLBoolean egl_window_surface_v2_t::connect() +{ + // we're intending to do software rendering + native_window_set_usage(nativeWindow, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + + // dequeue a buffer + if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) { + return setError(EGL_BAD_ALLOC, EGL_FALSE); + } + + // allocate a corresponding depth-buffer + width = buffer->width; + height = buffer->height; + if (depth.format) { + depth.width = width; + depth.height = height; + depth.stride = depth.width; // use the width here + assert(GGL_PIXEL_FORMAT_Z_32 == depth.format); + depth.data = (GGLubyte*)malloc(depth.stride*depth.height*4); + if (depth.data == 0) { + return setError(EGL_BAD_ALLOC, EGL_FALSE); + } + } + + // keep a reference on the buffer + buffer->common.incRef(&buffer->common); + + // Lock the buffer + nativeWindow->lockBuffer(nativeWindow, buffer); + // pin the buffer down + if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { + LOGE("connect() failed to lock buffer %p (%ux%u)", + buffer, buffer->width, buffer->height); + return setError(EGL_BAD_ACCESS, EGL_FALSE); + // FIXME: we should make sure we're not accessing the buffer anymore + } + return EGL_TRUE; +} + +void egl_window_surface_v2_t::disconnect() +{ + if (buffer && bits) { + bits = NULL; + unlock(buffer); + } + // enqueue the last frame + if (buffer) + nativeWindow->queueBuffer(nativeWindow, buffer); + if (buffer) { + buffer->common.decRef(&buffer->common); + buffer = 0; + } + if (previousBuffer) { + previousBuffer->common.decRef(&previousBuffer->common); + previousBuffer = 0; + } +} + +status_t egl_window_surface_v2_t::lock( + android_native_buffer_t* buf, int usage, void** vaddr) +{ + int err; + + err = module->lock(module, buf->handle, + usage, 0, 0, buf->width, buf->height, vaddr); + + return err; +} + +status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf) +{ + if (!buf) return BAD_VALUE; + int err = NO_ERROR; + + err = module->unlock(module, buf->handle); + + return err; +} + +void egl_window_surface_v2_t::copyBlt( + android_native_buffer_t* dst, void* dst_vaddr, + android_native_buffer_t* src, void const* src_vaddr, + const Region& clip) +{ + // FIXME: use copybit if possible + // NOTE: dst and src must be the same format + + status_t err = NO_ERROR; + copybit_device_t* const copybit = blitengine; + if (copybit) { + copybit_image_t simg; + simg.w = src->stride; + simg.h = src->height; + simg.format = src->format; + simg.handle = const_cast<native_handle_t*>(src->handle); + + copybit_image_t dimg; + dimg.w = dst->stride; + dimg.h = dst->height; + dimg.format = dst->format; + dimg.handle = const_cast<native_handle_t*>(dst->handle); + + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255); + copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); + region_iterator it(clip); + err = copybit->blit(copybit, &dimg, &simg, &it); + if (err != NO_ERROR) { + LOGE("copybit failed (%s)", strerror(err)); + } + } + + if (!copybit || err) { + Region::const_iterator cur = clip.begin(); + Region::const_iterator end = clip.end(); + + const size_t bpp = pixelFormatTable[src->format].size; + const size_t dbpr = dst->stride * bpp; + const size_t sbpr = src->stride * bpp; + + uint8_t const * const src_bits = (uint8_t const *)src_vaddr; + uint8_t * const dst_bits = (uint8_t *)dst_vaddr; + + while (cur != end) { + const Rect& r(*cur++); + ssize_t w = r.right - r.left; + ssize_t h = r.bottom - r.top; + if (w <= 0 || h<=0) continue; + size_t size = w * bpp; + uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; + uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; + if (dbpr==sbpr && size==sbpr) { + size *= h; + h = 1; + } + do { + memcpy(d, s, size); + d += dbpr; + s += sbpr; + } while (--h > 0); + } + } +} + +EGLBoolean egl_window_surface_v2_t::swapBuffers() +{ + if (!buffer) { + return setError(EGL_BAD_ACCESS, EGL_FALSE); + } + + /* + * Handle eglSetSwapRectangleANDROID() + * We copyback from the front buffer + */ + if (!dirtyRegion.isEmpty()) { + dirtyRegion.andSelf(Rect(buffer->width, buffer->height)); + if (previousBuffer) { + // This was const Region copyBack, but that causes an + // internal compile error on simulator builds + /*const*/ + Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion)); + if (!copyBack.isEmpty()) { + void* prevBits; + if (lock(previousBuffer, + GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) { + // copy from previousBuffer to buffer + copyBlt(buffer, bits, previousBuffer, prevBits, copyBack); + unlock(previousBuffer); + } + } + } + oldDirtyRegion = dirtyRegion; + } + + if (previousBuffer) { + previousBuffer->common.decRef(&previousBuffer->common); + previousBuffer = 0; + } + + unlock(buffer); + previousBuffer = buffer; + nativeWindow->queueBuffer(nativeWindow, buffer); + buffer = 0; + + // dequeue a new buffer + if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) { + + // TODO: lockBuffer should rather be executed when the very first + // direct rendering occurs. + nativeWindow->lockBuffer(nativeWindow, buffer); + + // reallocate the depth-buffer if needed + if ((width != buffer->width) || (height != buffer->height)) { + // TODO: we probably should reset the swap rect here + // if the window size has changed + width = buffer->width; + height = buffer->height; + if (depth.data) { + free(depth.data); + depth.width = width; + depth.height = height; + depth.stride = buffer->stride; + depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); + if (depth.data == 0) { + setError(EGL_BAD_ALLOC, EGL_FALSE); + return EGL_FALSE; + } + } + } + + // keep a reference on the buffer + buffer->common.incRef(&buffer->common); + + // finally pin the buffer down + if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { + LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)", + buffer, buffer->width, buffer->height); + return setError(EGL_BAD_ACCESS, EGL_FALSE); + // FIXME: we should make sure we're not accessing the buffer anymore + } + } else { + return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE); + } + + return EGL_TRUE; +} + +EGLBoolean egl_window_surface_v2_t::setSwapRectangle( + EGLint l, EGLint t, EGLint w, EGLint h) +{ + dirtyRegion = Rect(l, t, l+w, t+h); + return EGL_TRUE; +} + +EGLBoolean egl_window_surface_v2_t::bindDrawSurface(GLES2Context* gl) +{ + GGLSurface buffer; + buffer.version = sizeof(GGLSurface); + buffer.width = this->buffer->width; + buffer.height = this->buffer->height; + buffer.stride = this->buffer->stride; + buffer.data = (GGLubyte*)bits; + buffer.format = (GGLPixelFormat)this->buffer->format; + gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer); + if (depth.data != gl->rasterizer.depthSurface.data) + gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth); + + return EGL_TRUE; +} +EGLBoolean egl_window_surface_v2_t::bindReadSurface(GLES2Context* gl) +{ + GGLSurface buffer; + buffer.version = sizeof(GGLSurface); + buffer.width = this->buffer->width; + buffer.height = this->buffer->height; + buffer.stride = this->buffer->stride; + buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!! + buffer.format = (GGLPixelFormat)this->buffer->format; + puts("agl2: readBuffer not implemented"); + //gl->rasterizer.interface.readBuffer(gl, &buffer); + return EGL_TRUE; +} +EGLint egl_window_surface_v2_t::getHorizontalResolution() const +{ + return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); +} +EGLint egl_window_surface_v2_t::getVerticalResolution() const +{ + return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); +} +EGLint egl_window_surface_v2_t::getRefreshRate() const +{ + return (60 * EGL_DISPLAY_SCALING); // FIXME +} +EGLint egl_window_surface_v2_t::getSwapBehavior() const +{ + /* + * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves + * the content of the swapped buffer. + * + * EGL_BUFFER_DESTROYED means that the content of the buffer is lost. + * + * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED + * only applies to the area specified by eglSetSwapRectangleANDROID(), that + * is, everything outside of this area is preserved. + * + * This implementation of EGL assumes the later case. + * + */ + + return EGL_BUFFER_DESTROYED; +} + +// ---------------------------------------------------------------------------- + +struct egl_pixmap_surface_t : public egl_surface_t { + egl_pixmap_surface_t( + EGLDisplay dpy, EGLConfig config, + int32_t depthFormat, + egl_native_pixmap_t const * pixmap); + + virtual ~egl_pixmap_surface_t() { } + + virtual bool initCheck() const { + return !depth.format || depth.data!=0; + } + virtual EGLBoolean bindDrawSurface(GLES2Context* gl); + virtual EGLBoolean bindReadSurface(GLES2Context* gl); + virtual EGLint getWidth() const { + return nativePixmap.width; + } + virtual EGLint getHeight() const { + return nativePixmap.height; + } +private: + egl_native_pixmap_t nativePixmap; +}; + +egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy, + EGLConfig config, + int32_t depthFormat, + egl_native_pixmap_t const * pixmap) + : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap) +{ + if (depthFormat) { + depth.width = pixmap->width; + depth.height = pixmap->height; + depth.stride = depth.width; // use the width here + depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); + if (depth.data == 0) { + setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + } +} +EGLBoolean egl_pixmap_surface_t::bindDrawSurface(GLES2Context* gl) +{ + GGLSurface buffer; + buffer.version = sizeof(GGLSurface); + buffer.width = nativePixmap.width; + buffer.height = nativePixmap.height; + buffer.stride = nativePixmap.stride; + buffer.data = nativePixmap.data; + buffer.format = (GGLPixelFormat)nativePixmap.format; + + gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer); + if (depth.data != gl->rasterizer.depthSurface.data) + gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth); + return EGL_TRUE; +} +EGLBoolean egl_pixmap_surface_t::bindReadSurface(GLES2Context* gl) +{ + GGLSurface buffer; + buffer.version = sizeof(GGLSurface); + buffer.width = nativePixmap.width; + buffer.height = nativePixmap.height; + buffer.stride = nativePixmap.stride; + buffer.data = nativePixmap.data; + buffer.format = (GGLPixelFormat)nativePixmap.format; + puts("agl2: readBuffer not implemented"); + //gl->rasterizer.interface.readBuffer(gl, &buffer); + return EGL_TRUE; +} + +// ---------------------------------------------------------------------------- + +struct egl_pbuffer_surface_t : public egl_surface_t { + egl_pbuffer_surface_t( + EGLDisplay dpy, EGLConfig config, int32_t depthFormat, + int32_t w, int32_t h, int32_t f); + + virtual ~egl_pbuffer_surface_t(); + + virtual bool initCheck() const { + return pbuffer.data != 0; + } + virtual EGLBoolean bindDrawSurface(GLES2Context* gl); + virtual EGLBoolean bindReadSurface(GLES2Context* gl); + virtual EGLint getWidth() const { + return pbuffer.width; + } + virtual EGLint getHeight() const { + return pbuffer.height; + } +private: + GGLSurface pbuffer; +}; + +egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, + EGLConfig config, int32_t depthFormat, + int32_t w, int32_t h, int32_t f) + : egl_surface_t(dpy, config, depthFormat) +{ + size_t size = w*h; + switch (f) { + case GGL_PIXEL_FORMAT_A_8: + size *= 1; + break; + case GGL_PIXEL_FORMAT_RGB_565: + size *= 2; + break; + case GGL_PIXEL_FORMAT_RGBA_8888: + size *= 4; + break; + case GGL_PIXEL_FORMAT_RGBX_8888: + size *= 4; + break; + default: + LOGE("incompatible pixel format for pbuffer (format=%d)", f); + pbuffer.data = 0; + break; + } + pbuffer.version = sizeof(GGLSurface); + pbuffer.width = w; + pbuffer.height = h; + pbuffer.stride = w; + pbuffer.data = (GGLubyte*)malloc(size); + pbuffer.format = (GGLPixelFormat)f; + + if (depthFormat) { + depth.width = pbuffer.width; + depth.height = pbuffer.height; + depth.stride = depth.width; // use the width here + depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); + if (depth.data == 0) { + setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); + return; + } + } +} +egl_pbuffer_surface_t::~egl_pbuffer_surface_t() +{ + free(pbuffer.data); +} +EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(GLES2Context* gl) +{ + gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &pbuffer); + if (depth.data != gl->rasterizer.depthSurface.data) + gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth); + return EGL_TRUE; +} +EGLBoolean egl_pbuffer_surface_t::bindReadSurface(GLES2Context* gl) +{ + puts("agl2: readBuffer not implemented"); + //gl->rasterizer.interface.readBuffer(gl, &pbuffer); + return EGL_TRUE; +} + +// ---------------------------------------------------------------------------- + +struct config_pair_t { + GLint key; + GLint value; +}; + +struct configs_t { + const config_pair_t* array; + int size; +}; + +struct config_management_t { + GLint key; + bool (*match)(GLint reqValue, GLint confValue); + static bool atLeast(GLint reqValue, GLint confValue) { + return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue); + } + static bool exact(GLint reqValue, GLint confValue) { + return (reqValue == EGL_DONT_CARE) || (confValue == reqValue); + } + static bool mask(GLint reqValue, GLint confValue) { + return (confValue & reqValue) == reqValue; + } + static bool ignore(GLint reqValue, GLint confValue) { + return true; + } +}; + +// ---------------------------------------------------------------------------- + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 2 +static char const * const gVendorString = "Google Inc."; +static char const * const gVersionString = "0.0 Android Driver 0.0.0"; +static char const * const gClientApiString = "OpenGL ES2"; +static char const * const gExtensionsString = + //"EGL_KHR_image_base " + // "KHR_image_pixmap " + //"EGL_ANDROID_image_native_buffer " + //"EGL_ANDROID_swap_rectangle " + ""; + +// ---------------------------------------------------------------------------- + +struct extention_map_t { + const char * const name; + __eglMustCastToProperFunctionPointerType address; +}; + +static const extention_map_t gExtentionMap[] = { +// { "glDrawTexsOES", +// (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES }, +// { "glDrawTexiOES", +// (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES }, +// { "glDrawTexfOES", +// (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES }, +// { "glDrawTexxOES", +// (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES }, +// { "glDrawTexsvOES", +// (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES }, +// { "glDrawTexivOES", +// (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES }, +// { "glDrawTexfvOES", +// (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES }, +// { "glDrawTexxvOES", +// (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES }, +// { "glQueryMatrixxOES", +// (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES }, +// { "glEGLImageTargetTexture2DOES", +// (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES }, +// { "glEGLImageTargetRenderbufferStorageOES", +// (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES }, +// { "glClipPlanef", +// (__eglMustCastToProperFunctionPointerType)&glClipPlanef }, +// { "glClipPlanex", +// (__eglMustCastToProperFunctionPointerType)&glClipPlanex }, +// { "glBindBuffer", +// (__eglMustCastToProperFunctionPointerType)&glBindBuffer }, +// { "glBufferData", +// (__eglMustCastToProperFunctionPointerType)&glBufferData }, +// { "glBufferSubData", +// (__eglMustCastToProperFunctionPointerType)&glBufferSubData }, +// { "glDeleteBuffers", +// (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers }, +// { "glGenBuffers", +// (__eglMustCastToProperFunctionPointerType)&glGenBuffers }, +// { "eglCreateImageKHR", +// (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, +// { "eglDestroyImageKHR", +// (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, +// { "eglSetSwapRectangleANDROID", +// (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID }, +}; + +/* + * In the lists below, attributes names MUST be sorted. + * Additionally, all configs must be sorted according to + * the EGL specification. + */ + +static config_pair_t const config_base_attribute_list[] = { + { EGL_STENCIL_SIZE, 0 }, + { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG }, + { EGL_LEVEL, 0 }, + { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS }, + { EGL_MAX_PBUFFER_PIXELS, + GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS }, + { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS }, + { EGL_NATIVE_RENDERABLE, EGL_TRUE }, + { EGL_NATIVE_VISUAL_ID, 0 }, + { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGBA_8888 }, + { EGL_SAMPLES, 0 }, + { EGL_SAMPLE_BUFFERS, 0 }, + { EGL_TRANSPARENT_TYPE, EGL_NONE }, + { EGL_TRANSPARENT_BLUE_VALUE, 0 }, + { EGL_TRANSPARENT_GREEN_VALUE, 0 }, + { EGL_TRANSPARENT_RED_VALUE, 0 }, + { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE }, + { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE }, + { EGL_MIN_SWAP_INTERVAL, 1 }, + { EGL_MAX_SWAP_INTERVAL, 1 }, + { EGL_LUMINANCE_SIZE, 0 }, + { EGL_ALPHA_MASK_SIZE, 0 }, + { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER }, + { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT }, + { EGL_CONFORMANT, 0 } +}; + +// These configs can override the base attribute list +// NOTE: when adding a config here, don't forget to update eglCreate*Surface() + +// 565 configs +static config_pair_t const config_0_attribute_list[] = { + { EGL_BUFFER_SIZE, 16 }, + { EGL_ALPHA_SIZE, 0 }, + { EGL_BLUE_SIZE, 5 }, + { EGL_GREEN_SIZE, 6 }, + { EGL_RED_SIZE, 5 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 0 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 }, + { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +static config_pair_t const config_1_attribute_list[] = { + { EGL_BUFFER_SIZE, 16 }, + { EGL_ALPHA_SIZE, 0 }, + { EGL_BLUE_SIZE, 5 }, + { EGL_GREEN_SIZE, 6 }, + { EGL_RED_SIZE, 5 }, + { EGL_DEPTH_SIZE, 16 }, + { EGL_CONFIG_ID, 1 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 }, + { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +// RGB 888 configs +static config_pair_t const config_2_attribute_list[] = { + { EGL_BUFFER_SIZE, 32 }, + { EGL_ALPHA_SIZE, 0 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 6 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 }, + { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +static config_pair_t const config_3_attribute_list[] = { + { EGL_BUFFER_SIZE, 32 }, + { EGL_ALPHA_SIZE, 0 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 16 }, + { EGL_CONFIG_ID, 7 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 }, + { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +// 8888 configs +static config_pair_t const config_4_attribute_list[] = { + { EGL_BUFFER_SIZE, 32 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 2 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 }, + { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +static config_pair_t const config_5_attribute_list[] = { + { EGL_BUFFER_SIZE, 32 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 16 }, + { EGL_CONFIG_ID, 3 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 }, + { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +// A8 configs +static config_pair_t const config_6_attribute_list[] = { + { EGL_BUFFER_SIZE, 8 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 0 }, + { EGL_GREEN_SIZE, 0 }, + { EGL_RED_SIZE, 0 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 4 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 }, + { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +static config_pair_t const config_7_attribute_list[] = { + { EGL_BUFFER_SIZE, 8 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 0 }, + { EGL_GREEN_SIZE, 0 }, + { EGL_RED_SIZE, 0 }, + { EGL_DEPTH_SIZE, 16 }, + { EGL_CONFIG_ID, 5 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 }, + { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +static configs_t const gConfigs[] = { + { config_0_attribute_list, NELEM(config_0_attribute_list) }, + { config_1_attribute_list, NELEM(config_1_attribute_list) }, + { config_2_attribute_list, NELEM(config_2_attribute_list) }, + { config_3_attribute_list, NELEM(config_3_attribute_list) }, + { config_4_attribute_list, NELEM(config_4_attribute_list) }, + { config_5_attribute_list, NELEM(config_5_attribute_list) }, +// { config_6_attribute_list, NELEM(config_6_attribute_list) }, +// { config_7_attribute_list, NELEM(config_7_attribute_list) }, +}; + +static config_management_t const gConfigManagement[] = { + { EGL_BUFFER_SIZE, config_management_t::atLeast }, + { EGL_ALPHA_SIZE, config_management_t::atLeast }, + { EGL_BLUE_SIZE, config_management_t::atLeast }, + { EGL_GREEN_SIZE, config_management_t::atLeast }, + { EGL_RED_SIZE, config_management_t::atLeast }, + { EGL_DEPTH_SIZE, config_management_t::atLeast }, + { EGL_STENCIL_SIZE, config_management_t::atLeast }, + { EGL_CONFIG_CAVEAT, config_management_t::exact }, + { EGL_CONFIG_ID, config_management_t::exact }, + { EGL_LEVEL, config_management_t::exact }, + { EGL_MAX_PBUFFER_HEIGHT, config_management_t::ignore }, + { EGL_MAX_PBUFFER_PIXELS, config_management_t::ignore }, + { EGL_MAX_PBUFFER_WIDTH, config_management_t::ignore }, + { EGL_NATIVE_RENDERABLE, config_management_t::exact }, + { EGL_NATIVE_VISUAL_ID, config_management_t::ignore }, + { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact }, + { EGL_SAMPLES, config_management_t::exact }, + { EGL_SAMPLE_BUFFERS, config_management_t::exact }, + { EGL_SURFACE_TYPE, config_management_t::mask }, + { EGL_TRANSPARENT_TYPE, config_management_t::exact }, + { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact }, + { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact }, + { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact }, + { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact }, + { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact }, + { EGL_MIN_SWAP_INTERVAL, config_management_t::exact }, + { EGL_MAX_SWAP_INTERVAL, config_management_t::exact }, + { EGL_LUMINANCE_SIZE, config_management_t::atLeast }, + { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast }, + { EGL_COLOR_BUFFER_TYPE, config_management_t::exact }, + { EGL_RENDERABLE_TYPE, config_management_t::mask }, + { EGL_CONFORMANT, config_management_t::mask } +}; + + +static config_pair_t const config_defaults[] = { + // attributes that are not specified are simply ignored, if a particular + // one needs not be ignored, it must be specified here, eg: + // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT }, +}; + +// ---------------------------------------------------------------------------- + +static status_t getConfigFormatInfo(EGLint configID, + int32_t& pixelFormat, int32_t& depthFormat) +{ + switch (configID) { + case 0: + pixelFormat = GGL_PIXEL_FORMAT_RGB_565; + depthFormat = 0; + break; + case 1: + pixelFormat = GGL_PIXEL_FORMAT_RGB_565; + depthFormat = GGL_PIXEL_FORMAT_Z_32; + break; + case 2: + pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; + depthFormat = 0; + break; + case 3: + pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; + depthFormat = GGL_PIXEL_FORMAT_Z_32; + break; + case 4: + pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; + depthFormat = 0; + break; + case 5: + pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; + depthFormat = GGL_PIXEL_FORMAT_Z_32; + break; + case 6: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = 0; + break; + case 7: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = GGL_PIXEL_FORMAT_Z_32; + break; + default: + return NAME_NOT_FOUND; + } + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + +template<typename T> +static int binarySearch(T const sortedArray[], int first, int last, EGLint key) +{ + while (first <= last) { + int mid = (first + last) / 2; + if (key > sortedArray[mid].key) { + first = mid + 1; + } else if (key < sortedArray[mid].key) { + last = mid - 1; + } else { + return mid; + } + } + return -1; +} + +static int isAttributeMatching(int i, EGLint attr, EGLint val) +{ + // look for the attribute in all of our configs + config_pair_t const* configFound = gConfigs[i].array; + int index = binarySearch<config_pair_t>( + gConfigs[i].array, + 0, gConfigs[i].size-1, + attr); + if (index < 0) { + configFound = config_base_attribute_list; + index = binarySearch<config_pair_t>( + config_base_attribute_list, + 0, NELEM(config_base_attribute_list)-1, + attr); + } + if (index >= 0) { + // attribute found, check if this config could match + int cfgMgtIndex = binarySearch<config_management_t>( + gConfigManagement, + 0, NELEM(gConfigManagement)-1, + attr); + if (cfgMgtIndex >= 0) { + bool match = gConfigManagement[cfgMgtIndex].match( + val, configFound[index].value); + if (match) { + // this config matches + return 1; + } + } else { + // attribute not found. this should NEVER happen. + } + } else { + // error, this attribute doesn't exist + } + return 0; +} + +static int makeCurrent(GLES2Context* gl) +{ + GLES2Context* current = (GLES2Context*)getGlThreadSpecific(); + if (gl) { + egl_context_t* c = egl_context_t::context(gl); + if (c->flags & egl_context_t::IS_CURRENT) { + if (current != gl) { + // it is an error to set a context current, if it's already + // current to another thread + return -1; + } + } else { + if (current) { + // mark the current context as not current, and flush + glFlush(); + egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT; + } + } + if (!(c->flags & egl_context_t::IS_CURRENT)) { + // The context is not current, make it current! + setGlThreadSpecific(gl); + c->flags |= egl_context_t::IS_CURRENT; + } + } else { + if (current) { + // mark the current context as not current, and flush + glFlush(); + egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT; + } + // this thread has no context attached to it + setGlThreadSpecific(0); + } + return 0; +} + +static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value) +{ + size_t numConfigs = NELEM(gConfigs); + int index = (int)config; + if (uint32_t(index) >= numConfigs) + return setError(EGL_BAD_CONFIG, EGL_FALSE); + + int attrIndex; + attrIndex = binarySearch<config_pair_t>( + gConfigs[index].array, + 0, gConfigs[index].size-1, + attribute); + if (attrIndex>=0) { + *value = gConfigs[index].array[attrIndex].value; + return EGL_TRUE; + } + + attrIndex = binarySearch<config_pair_t>( + config_base_attribute_list, + 0, NELEM(config_base_attribute_list)-1, + attribute); + if (attrIndex>=0) { + *value = config_base_attribute_list[attrIndex].value; + return EGL_TRUE; + } + return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); +} + +static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config, + NativeWindowType window, const EGLint *attrib_list) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); + if (window == 0) + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + + EGLint surfaceType; + if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) + return EGL_FALSE; + + if (!(surfaceType & EGL_WINDOW_BIT)) + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + + if (reinterpret_cast<ANativeWindow*>(window)->common.magic != + ANDROID_NATIVE_WINDOW_MAGIC) { + return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + EGLint configID; + if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) + return EGL_FALSE; + + int32_t depthFormat; + int32_t pixelFormat; + if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + // FIXME: we don't have access to the pixelFormat here just yet. + // (it's possible that the surface is not fully initialized) + // maybe this should be done after the page-flip + //if (EGLint(info.format) != pixelFormat) + // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + + egl_surface_t* surface; + surface = new egl_window_surface_v2_t(dpy, config, depthFormat, + reinterpret_cast<ANativeWindow*>(window)); + + if (!surface->initCheck()) { + // there was a problem in the ctor, the error + // flag has been set. + delete surface; + surface = 0; + } + return surface; +} + +static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config, + NativePixmapType pixmap, const EGLint *attrib_list) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); + if (pixmap == 0) + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + + EGLint surfaceType; + if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) + return EGL_FALSE; + + if (!(surfaceType & EGL_PIXMAP_BIT)) + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + + if (reinterpret_cast<egl_native_pixmap_t*>(pixmap)->version != + sizeof(egl_native_pixmap_t)) { + return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE); + } + + EGLint configID; + if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) + return EGL_FALSE; + + int32_t depthFormat; + int32_t pixelFormat; + if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + if (reinterpret_cast<egl_native_pixmap_t *>(pixmap)->format != pixelFormat) + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + + egl_surface_t* surface = + new egl_pixmap_surface_t(dpy, config, depthFormat, + reinterpret_cast<egl_native_pixmap_t*>(pixmap)); + + if (!surface->initCheck()) { + // there was a problem in the ctor, the error + // flag has been set. + delete surface; + surface = 0; + } + return surface; +} + +static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); + + EGLint surfaceType; + if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) + return EGL_FALSE; + + if (!(surfaceType & EGL_PBUFFER_BIT)) + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + + EGLint configID; + if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) + return EGL_FALSE; + + int32_t depthFormat; + int32_t pixelFormat; + if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { + return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + int32_t w = 0; + int32_t h = 0; + while (attrib_list[0]) { + if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1]; + if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1]; + attrib_list+=2; + } + + egl_surface_t* surface = + new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat); + + if (!surface->initCheck()) { + // there was a problem in the ctor, the error + // flag has been set. + delete surface; + surface = 0; + } + return surface; +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- + +using namespace android; + +// ---------------------------------------------------------------------------- +// Initialization +// ---------------------------------------------------------------------------- + +EGLDisplay eglGetDisplay(NativeDisplayType display) +{ + puts("agl2:eglGetDisplay"); +#ifndef HAVE_ANDROID_OS + // this just needs to be done once + if (gGLKey == -1) { + pthread_mutex_lock(&gInitMutex); + if (gGLKey == -1) + pthread_key_create(&gGLKey, NULL); + pthread_mutex_unlock(&gInitMutex); + } +#endif + if (display == EGL_DEFAULT_DISPLAY) { + EGLDisplay dpy = (EGLDisplay)1; + egl_display_t& d = egl_display_t::get_display(dpy); + d.type = display; + return dpy; + } + return EGL_NO_DISPLAY; +} + +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + puts("agl2:eglInitialize"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + EGLBoolean res = EGL_TRUE; + egl_display_t& d = egl_display_t::get_display(dpy); + + if (android_atomic_inc(&d.initialized) == 0) { + // initialize stuff here if needed + //pthread_mutex_lock(&gInitMutex); + //pthread_mutex_unlock(&gInitMutex); + } + + if (res == EGL_TRUE) { + if (major != NULL) *major = VERSION_MAJOR; + if (minor != NULL) *minor = VERSION_MINOR; + } + return res; +} + +EGLBoolean eglTerminate(EGLDisplay dpy) +{ + puts("agl2:eglTerminate"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + EGLBoolean res = EGL_TRUE; + egl_display_t& d = egl_display_t::get_display(dpy); + if (android_atomic_dec(&d.initialized) == 1) { + // TODO: destroy all resources (surfaces, contexts, etc...) + //pthread_mutex_lock(&gInitMutex); + //pthread_mutex_unlock(&gInitMutex); + } + return res; +} + +// ---------------------------------------------------------------------------- +// configuration +// ---------------------------------------------------------------------------- + +EGLBoolean eglGetConfigs( EGLDisplay dpy, + EGLConfig *configs, + EGLint config_size, EGLint *num_config) +{ + puts("agl2:eglGetConfigs"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + GLint numConfigs = NELEM(gConfigs); + if (!configs) { + *num_config = numConfigs; + return EGL_TRUE; + } + GLint i; + for (i=0 ; i<numConfigs && i<config_size ; i++) { + *configs++ = (EGLConfig)i; + } + *num_config = i; + return EGL_TRUE; +} + +static const char * ATTRIBUTE_NAMES [] = { + "EGL_BUFFER_SIZE", + "EGL_ALPHA_SIZE", + "EGL_BLUE_SIZE", + "EGL_GREEN_SIZE", + "EGL_RED_SIZE", + "EGL_DEPTH_SIZE", + "EGL_STENCIL_SIZE", + "EGL_CONFIG_CAVEAT", + "EGL_CONFIG_ID", + "EGL_LEVEL", + "EGL_MAX_PBUFFER_HEIGHT", + "EGL_MAX_PBUFFER_PIXELS", + "EGL_MAX_PBUFFER_WIDTH", + "EGL_NATIVE_RENDERABLE", + "EGL_NATIVE_VISUAL_ID", + "EGL_NATIVE_VISUAL_TYPE", + "EGL_PRESERVED_RESOURCES", + "EGL_SAMPLES", + "EGL_SAMPLE_BUFFERS", + "EGL_SURFACE_TYPE", + "EGL_TRANSPARENT_TYPE", + "EGL_TRANSPARENT_BLUE_VALUE", + "EGL_TRANSPARENT_GREEN_VALUE", + "EGL_TRANSPARENT_RED_VALUE", + "EGL_NONE", /* Attrib list terminator */ + "EGL_BIND_TO_TEXTURE_RGB", + "EGL_BIND_TO_TEXTURE_RGBA", + "EGL_MIN_SWAP_INTERVAL", + "EGL_MAX_SWAP_INTERVAL", + "EGL_LUMINANCE_SIZE", + "EGL_ALPHA_MASK_SIZE", + "EGL_COLOR_BUFFER_TYPE", + "EGL_RENDERABLE_TYPE", + "EGL_MATCH_NATIVE_PIXMAP", /* Pseudo-attribute (not queryable) */ + "EGL_CONFORMANT", +}; + +EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config) +{ + puts("agl2:eglChooseConfig"); + LOGD("\n***\n***\n agl2:LOGD eglChooseConfig \n***\n***\n"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + if (ggl_unlikely(num_config==0)) { + LOGD("\n***\n***\n num_config==0 \n***\n***\n"); + return setError(EGL_BAD_PARAMETER, EGL_FALSE); + } + + if (ggl_unlikely(attrib_list==0)) { + /* + * A NULL attrib_list should be treated as though it was an empty + * one (terminated with EGL_NONE) as defined in + * section 3.4.1 "Querying Configurations" in the EGL specification. + */ + LOGD("\n***\n***\n attrib_list==0 \n***\n***\n"); + static const EGLint dummy = EGL_NONE; + attrib_list = &dummy; + } + + for (const EGLint * attrib = attrib_list; *attrib != EGL_NONE; attrib += 2) { + LOGD("eglChooseConfig %s(%.4X): %d \n", ATTRIBUTE_NAMES[attrib[0] - EGL_BUFFER_SIZE], attrib[0], attrib[1]); + if (EGL_BUFFER_SIZE > attrib[0] || EGL_CONFORMANT < attrib[0]) + LOGD("eglChooseConfig invalid config attrib: 0x%.4X=%d \n", attrib[0], attrib[1]); + } + + int numAttributes = 0; + int numConfigs = NELEM(gConfigs); + uint32_t possibleMatch = (1<<numConfigs)-1; + while (possibleMatch && *attrib_list != EGL_NONE) { + numAttributes++; + EGLint attr = *attrib_list++; + EGLint val = *attrib_list++; + for (int i=0 ; possibleMatch && i<numConfigs ; i++) { + if (!(possibleMatch & (1<<i))) + continue; + if (isAttributeMatching(i, attr, val) == 0) { + LOGD("!isAttributeMatching config(%d) %s=%d \n", i, ATTRIBUTE_NAMES[attr - EGL_BUFFER_SIZE], val); + possibleMatch &= ~(1<<i); + } + } + } + + LOGD("eglChooseConfig possibleMatch=%.4X \n", possibleMatch); + + // now, handle the attributes which have a useful default value + for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) { + // see if this attribute was specified, if not, apply its + // default value + if (binarySearch<config_pair_t>( + (config_pair_t const*)attrib_list, + 0, numAttributes-1, + config_defaults[j].key) < 0) { + for (int i=0 ; possibleMatch && i<numConfigs ; i++) { + if (!(possibleMatch & (1<<i))) + continue; + if (isAttributeMatching(i, + config_defaults[j].key, + config_defaults[j].value) == 0) { + possibleMatch &= ~(1<<i); + } + } + } + } + + // return the configurations found + int n=0; + if (possibleMatch) { + if (configs) { + for (int i=0 ; config_size && i<numConfigs ; i++) { + if (possibleMatch & (1<<i)) { + *configs++ = (EGLConfig)i; + config_size--; + n++; + } + } + } else { + for (int i=0 ; i<numConfigs ; i++) { + if (possibleMatch & (1<<i)) { + n++; + } + } + } + } + *num_config = n; + LOGD("\n***\n***\n num_config==%d \n***\n***\n", *num_config); + return EGL_TRUE; +} + +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value) +{ + puts("agl2:eglGetConfigAttrib"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + return getConfigAttrib(dpy, config, attribute, value); +} + +// ---------------------------------------------------------------------------- +// surfaces +// ---------------------------------------------------------------------------- + +EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) +{ + puts("agl2:eglCreateWindowSurface"); + return createWindowSurface(dpy, config, window, attrib_list); +} + +EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, + NativePixmapType pixmap, + const EGLint *attrib_list) +{ + puts("agl2:eglCreatePixmapSurface"); + return createPixmapSurface(dpy, config, pixmap, attrib_list); +} + +EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ + puts("agl2:eglCreatePbufferSurface"); + return createPbufferSurface(dpy, config, attrib_list); +} + +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface) +{ + puts("agl2:eglDestroySurface"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + if (eglSurface != EGL_NO_SURFACE) { + egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) ); + if (!surface->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (surface->dpy != dpy) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + if (surface->ctx) { + // FIXME: this surface is current check what the spec says + surface->disconnect(); + surface->ctx = 0; + } + delete surface; + } + return EGL_TRUE; +} + +EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface, + EGLint attribute, EGLint *value) +{ + puts("agl2:eglQuerySurface"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface); + if (!surface->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (surface->dpy != dpy) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + EGLBoolean ret = EGL_TRUE; + switch (attribute) { + case EGL_CONFIG_ID: + ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value); + break; + case EGL_WIDTH: + *value = surface->getWidth(); + break; + case EGL_HEIGHT: + *value = surface->getHeight(); + break; + case EGL_LARGEST_PBUFFER: + // not modified for a window or pixmap surface + break; + case EGL_TEXTURE_FORMAT: + *value = EGL_NO_TEXTURE; + break; + case EGL_TEXTURE_TARGET: + *value = EGL_NO_TEXTURE; + break; + case EGL_MIPMAP_TEXTURE: + *value = EGL_FALSE; + break; + case EGL_MIPMAP_LEVEL: + *value = 0; + break; + case EGL_RENDER_BUFFER: + // TODO: return the real RENDER_BUFFER here + *value = EGL_BACK_BUFFER; + break; + case EGL_HORIZONTAL_RESOLUTION: + // pixel/mm * EGL_DISPLAY_SCALING + *value = surface->getHorizontalResolution(); + break; + case EGL_VERTICAL_RESOLUTION: + // pixel/mm * EGL_DISPLAY_SCALING + *value = surface->getVerticalResolution(); + break; + case EGL_PIXEL_ASPECT_RATIO: { + // w/h * EGL_DISPLAY_SCALING + int wr = surface->getHorizontalResolution(); + int hr = surface->getVerticalResolution(); + *value = (wr * EGL_DISPLAY_SCALING) / hr; + } + break; + case EGL_SWAP_BEHAVIOR: + *value = surface->getSwapBehavior(); + break; + default: + ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + return ret; +} + +EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_list, const EGLint *attrib_list) +{ + puts("agl2:eglCreateContext"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); + + GLES2Context* gl = new GLES2Context();//ogles_init(sizeof(egl_context_t)); + if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + + //egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base); + egl_context_t * c = &gl->egl; + c->flags = egl_context_t::NEVER_CURRENT; + c->dpy = dpy; + c->config = config; + c->read = 0; + c->draw = 0; + + c->frame = 0; + c->lastSwapTime = clock(); + c->accumulateSeconds = 0; + return (EGLContext)gl; +} + +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + puts("agl2:eglDestroyContext"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + egl_context_t* c = egl_context_t::context(ctx); + if (c->flags & egl_context_t::IS_CURRENT) + setGlThreadSpecific(0); + //ogles_uninit((GLES2Context*)ctx); + delete (GLES2Context*)ctx; + return EGL_TRUE; +} + +EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx) +{ + puts("agl2:eglMakeCurrent"); + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + if (draw) { + egl_surface_t* s = (egl_surface_t*)draw; + if (!s->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (s->dpy != dpy) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // TODO: check that draw is compatible with the context + } + if (read && read!=draw) { + egl_surface_t* s = (egl_surface_t*)read; + if (!s->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (s->dpy != dpy) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // TODO: check that read is compatible with the context + } + + EGLContext current_ctx = EGL_NO_CONTEXT; + + if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT)) + return setError(EGL_BAD_MATCH, EGL_FALSE); + + if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT)) + return setError(EGL_BAD_MATCH, EGL_FALSE); + + if (ctx == EGL_NO_CONTEXT) { + // if we're detaching, we need the current context + current_ctx = (EGLContext)getGlThreadSpecific(); + } else { + egl_context_t* c = egl_context_t::context(ctx); + egl_surface_t* d = (egl_surface_t*)draw; + egl_surface_t* r = (egl_surface_t*)read; + if ((d && d->ctx && d->ctx != ctx) || + (r && r->ctx && r->ctx != ctx)) { + // one of the surface is bound to a context in another thread + return setError(EGL_BAD_ACCESS, EGL_FALSE); + } + } + + GLES2Context* gl = (GLES2Context*)ctx; + if (makeCurrent(gl) == 0) { + if (ctx) { + egl_context_t* c = egl_context_t::context(ctx); + egl_surface_t* d = (egl_surface_t*)draw; + egl_surface_t* r = (egl_surface_t*)read; + + if (c->draw) { + egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw); + s->disconnect(); + } + if (c->read) { + // FIXME: unlock/disconnect the read surface too + } + + c->draw = draw; + c->read = read; + + if (c->flags & egl_context_t::NEVER_CURRENT) { + c->flags &= ~egl_context_t::NEVER_CURRENT; + GLint w = 0; + GLint h = 0; + if (draw) { + w = d->getWidth(); + h = d->getHeight(); + } + gl->rasterizer.interface.Viewport(&gl->rasterizer.interface, 0, 0, w, h); + //ogles_surfaceport(gl, 0, 0); + //ogles_viewport(gl, 0, 0, w, h); + //ogles_scissor(gl, 0, 0, w, h); + } + if (d) { + if (d->connect() == EGL_FALSE) { + return EGL_FALSE; + } + d->ctx = ctx; + d->bindDrawSurface(gl); + } + if (r) { + // FIXME: lock/connect the read surface too + r->ctx = ctx; + r->bindReadSurface(gl); + } + } else { + // if surfaces were bound to the context bound to this thread + // mark then as unbound. + if (current_ctx) { + egl_context_t* c = egl_context_t::context(current_ctx); + egl_surface_t* d = (egl_surface_t*)c->draw; + egl_surface_t* r = (egl_surface_t*)c->read; + if (d) { + c->draw = 0; + d->ctx = EGL_NO_CONTEXT; + d->disconnect(); + } + if (r) { + c->read = 0; + r->ctx = EGL_NO_CONTEXT; + // FIXME: unlock/disconnect the read surface too + } + } + } + return EGL_TRUE; + } + return setError(EGL_BAD_ACCESS, EGL_FALSE); +} + +EGLContext eglGetCurrentContext(void) +{ + // eglGetCurrentContext returns the current EGL rendering context, + // as specified by eglMakeCurrent. If no context is current, + // EGL_NO_CONTEXT is returned. + return (EGLContext)getGlThreadSpecific(); +} + +EGLSurface eglGetCurrentSurface(EGLint readdraw) +{ + // eglGetCurrentSurface returns the read or draw surface attached + // to the current EGL rendering context, as specified by eglMakeCurrent. + // If no context is current, EGL_NO_SURFACE is returned. + EGLContext ctx = (EGLContext)getGlThreadSpecific(); + if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE; + egl_context_t* c = egl_context_t::context(ctx); + if (readdraw == EGL_READ) { + return c->read; + } else if (readdraw == EGL_DRAW) { + return c->draw; + } + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); +} + +EGLDisplay eglGetCurrentDisplay(void) +{ + // eglGetCurrentDisplay returns the current EGL display connection + // for the current EGL rendering context, as specified by eglMakeCurrent. + // If no context is current, EGL_NO_DISPLAY is returned. + EGLContext ctx = (EGLContext)getGlThreadSpecific(); + if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY; + egl_context_t* c = egl_context_t::context(ctx); + return c->dpy; +} + +EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + egl_context_t* c = egl_context_t::context(ctx); + switch (attribute) { + case EGL_CONFIG_ID: + // Returns the ID of the EGL frame buffer configuration with + // respect to which the context was created + return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value); + } + return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); +} + +EGLBoolean eglWaitGL(void) +{ + return EGL_TRUE; +} + +EGLBoolean eglWaitNative(EGLint engine) +{ + return EGL_TRUE; +} + +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + egl_surface_t* d = static_cast<egl_surface_t*>(draw); + if (!d->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (d->dpy != dpy) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + // post the surface + d->swapBuffers(); + + // if it's bound to a context, update the buffer + if (d->ctx != EGL_NO_CONTEXT) { + d->bindDrawSurface((GLES2Context*)d->ctx); + // if this surface is also the read surface of the context + // it is bound to, make sure to update the read buffer as well. + // The EGL spec is a little unclear about this. + egl_context_t* c = egl_context_t::context(d->ctx); + if (c->read == draw) { + d->bindReadSurface((GLES2Context*)d->ctx); + } + clock_t time = clock(); + float elapsed = (float)(time - c->lastSwapTime) / CLOCKS_PER_SEC; + c->accumulateSeconds += elapsed; + c->frame++; +// LOGD("agl2: eglSwapBuffers elapsed=%.2fms \n*", elapsed * 1000); + if (20 == c->frame) { + float avg = c->accumulateSeconds / c->frame; + LOGD("\n*\n* agl2: eglSwapBuffers %u frame avg fps=%.1f elapsed=%.2fms \n*", + c->frame, 1 / avg, avg * 1000); + c->frame = 0; + c->accumulateSeconds = 0; + } + c->lastSwapTime = time; + } + + return EGL_TRUE; +} + +EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, + NativePixmapType target) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // TODO: eglCopyBuffers() + return EGL_FALSE; +} + +EGLint eglGetError(void) +{ + return getError(); +} + +const char* eglQueryString(EGLDisplay dpy, EGLint name) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, (const char*)0); + + switch (name) { + case EGL_VENDOR: + return gVendorString; + case EGL_VERSION: + return gVersionString; + case EGL_EXTENSIONS: + return gExtensionsString; + case EGL_CLIENT_APIS: + return gClientApiString; + } + return setError(EGL_BAD_PARAMETER, (const char *)0); +} + +// ---------------------------------------------------------------------------- +// EGL 1.1 +// ---------------------------------------------------------------------------- + +EGLBoolean eglSurfaceAttrib( + EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // TODO: eglSurfaceAttrib() + return setError(EGL_BAD_PARAMETER, EGL_FALSE); +} + +EGLBoolean eglBindTexImage( + EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // TODO: eglBindTexImage() + return setError(EGL_BAD_PARAMETER, EGL_FALSE); +} + +EGLBoolean eglReleaseTexImage( + EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // TODO: eglReleaseTexImage() + return setError(EGL_BAD_PARAMETER, EGL_FALSE); +} + +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // TODO: eglSwapInterval() + return EGL_TRUE; +} + +// ---------------------------------------------------------------------------- +// EGL 1.2 +// ---------------------------------------------------------------------------- + +EGLBoolean eglBindAPI(EGLenum api) +{ + if (api != EGL_OPENGL_ES_API) + return setError(EGL_BAD_PARAMETER, EGL_FALSE); + return EGL_TRUE; +} + +EGLenum eglQueryAPI(void) +{ + return EGL_OPENGL_ES_API; +} + +EGLBoolean eglWaitClient(void) +{ + glFinish(); + return EGL_TRUE; +} + +EGLBoolean eglReleaseThread(void) +{ + // TODO: eglReleaseThread() + return EGL_TRUE; +} + +EGLSurface eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); + // TODO: eglCreatePbufferFromClientBuffer() + return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); +} + +// ---------------------------------------------------------------------------- +// EGL_EGLEXT_VERSION 3 +// ---------------------------------------------------------------------------- + +void (*eglGetProcAddress (const char *procname))() +{ + extention_map_t const * const map = gExtentionMap; + for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) { + if (!strcmp(procname, map[i].name)) { + return map[i].address; + } + } + return NULL; +} + +EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, + const EGLint *attrib_list) +{ + EGLBoolean result = EGL_FALSE; + return result; +} + +EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) +{ + EGLBoolean result = EGL_FALSE; + return result; +} + +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attrib_list) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) { + return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR); + } + if (ctx != EGL_NO_CONTEXT) { + return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); + } + if (target != EGL_NATIVE_BUFFER_ANDROID) { + return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + } + + android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer; + + if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) + return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + + if (native_buffer->common.version != sizeof(android_native_buffer_t)) + return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + + switch (native_buffer->format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGB_888: + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + break; + default: + return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); + } + + native_buffer->common.incRef(&native_buffer->common); + return (EGLImageKHR)native_buffer; +} + +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) { + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + } + + android_native_buffer_t* native_buffer = (android_native_buffer_t*)img; + + if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) + return setError(EGL_BAD_PARAMETER, EGL_FALSE); + + if (native_buffer->common.version != sizeof(android_native_buffer_t)) + return setError(EGL_BAD_PARAMETER, EGL_FALSE); + + native_buffer->common.decRef(&native_buffer->common); + + return EGL_TRUE; +} + +// ---------------------------------------------------------------------------- +// ANDROID extensions +// ---------------------------------------------------------------------------- + +EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, + EGLint left, EGLint top, EGLint width, EGLint height) +{ + if (egl_display_t::is_valid(dpy) == EGL_FALSE) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + egl_surface_t* d = static_cast<egl_surface_t*>(draw); + if (!d->isValid()) + return setError(EGL_BAD_SURFACE, EGL_FALSE); + if (d->dpy != dpy) + return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + // post the surface + d->setSwapRectangle(left, top, width, height); + + return EGL_TRUE; +} diff --git a/opengl/libagl2/src/get.cpp b/opengl/libagl2/src/get.cpp new file mode 100644 index 0000000..13c28ce --- /dev/null +++ b/opengl/libagl2/src/get.cpp @@ -0,0 +1,79 @@ +#include "gles2context.h" + +static char const * const gVendorString = "Android"; +static char const * const gRendererString = "Android PixelFlinger2 0.0"; +static char const * const gVersionString = "OpenGL ES 2.0"; +static char const * const gExtensionsString = +// "GL_OES_byte_coordinates " // OK +// "GL_OES_fixed_point " // OK +// "GL_OES_single_precision " // OK +// "GL_OES_read_format " // OK +// "GL_OES_compressed_paletted_texture " // OK +// "GL_OES_draw_texture " // OK +// "GL_OES_matrix_get " // OK +// "GL_OES_query_matrix " // OK +// // "GL_OES_point_size_array " // TODO +// // "GL_OES_point_sprite " // TODO +// "GL_OES_EGL_image " // OK +//#ifdef GL_OES_compressed_ETC1_RGB8_texture +// "GL_OES_compressed_ETC1_RGB8_texture " // OK +//#endif +// "GL_ARB_texture_compression " // OK +// "GL_ARB_texture_non_power_of_two " // OK +// "GL_ANDROID_user_clip_plane " // OK +// "GL_ANDROID_vertex_buffer_object " // OK +// "GL_ANDROID_generate_mipmap " // OK + "" + ; + +void glGetIntegerv(GLenum pname, GLint* params) +{ + switch (pname) { + case GL_MAX_TEXTURE_SIZE : + *params = 4096; // limit is in precision of texcoord calculation, which uses 16.16 + break; + case GL_MAX_VERTEX_ATTRIBS: + *params = GGL_MAXVERTEXATTRIBS; + break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: + *params = GGL_MAXVERTEXUNIFORMVECTORS; + break; + case GL_MAX_VARYING_VECTORS: + *params = GGL_MAXVARYINGVECTORS; + break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + *params = GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; + break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: + *params = GGL_MAXVERTEXTEXTUREIMAGEUNITS; + break; + case GL_MAX_TEXTURE_IMAGE_UNITS: + *params = GGL_MAXTEXTUREIMAGEUNITS; + break; + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: + *params = GGL_MAXFRAGMENTUNIFORMVECTORS; + break; + case GL_ALIASED_LINE_WIDTH_RANGE: + *params = 1; // TODO: not implemented + break; + default: + LOGD("agl2: glGetIntegerv 0x%.4X", pname); + assert(0); + } +} + +const GLubyte* glGetString(GLenum name) +{ + switch (name) { + case GL_VENDOR: + return (const GLubyte*)gVendorString; + case GL_RENDERER: + return (const GLubyte*)gRendererString; + case GL_VERSION: + return (const GLubyte*)gVersionString; + case GL_EXTENSIONS: + return (const GLubyte*)gExtensionsString; + } + assert(0); //(c, GL_INVALID_ENUM); + return 0; +} diff --git a/opengl/libagl2/src/gles2context.h b/opengl/libagl2/src/gles2context.h new file mode 100644 index 0000000..cec0340 --- /dev/null +++ b/opengl/libagl2/src/gles2context.h @@ -0,0 +1,166 @@ +#define _SIZE_T_DEFINED_ +typedef unsigned int size_t; + +#include <stdio.h> +#include <stdlib.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES/gl.h> +#include <GLES/glext.h> + +#include <utils/threads.h> +#include <pthread.h> + +#include <cutils/log.h> + +#include <assert.h> + +#ifdef __arm__ +#ifndef __location__ +#define __HIERALLOC_STRING_0__(s) #s +#define __HIERALLOC_STRING_1__(s) __HIERALLOC_STRING_0__(s) +#define __HIERALLOC_STRING_2__ __HIERALLOC_STRING_1__(__LINE__) +#define __location__ __FILE__ ":" __HIERALLOC_STRING_2__ +#endif +#undef assert +#define assert(EXPR) { do { if (!(EXPR)) {LOGD("\n*\n*\n*\n* assert fail: '"#EXPR"' at "__location__"\n*\n*\n*\n*"); exit(EXIT_FAILURE); } } while (false); } +//#define printf LOGD +#else // #ifdef __arm__ +//#define LOGD printf +#endif // #ifdef __arm__ + + +#include <pixelflinger2/pixelflinger2_format.h> +#include <pixelflinger2/pixelflinger2.h> + +#include <map> + +typedef uint8_t GGLubyte; // ub + +#define ggl_likely(x) __builtin_expect(!!(x), 1) +#define ggl_unlikely(x) __builtin_expect(!!(x), 0) + +#undef NELEM +#define NELEM(x) (sizeof(x)/sizeof(*(x))) + +template<typename T> +inline T max(T a, T b) +{ + return a<b ? b : a; +} + +template<typename T> +inline T min(T a, T b) +{ + return a<b ? a : b; +} + +struct egl_context_t { + enum { + IS_CURRENT = 0x00010000, + NEVER_CURRENT = 0x00020000 + }; + uint32_t flags; + EGLDisplay dpy; + EGLConfig config; + EGLSurface read; + EGLSurface draw; + + unsigned frame; + clock_t lastSwapTime; + float accumulateSeconds; + + static inline egl_context_t* context(EGLContext ctx); +}; + +struct GLES2Context; + +#ifdef HAVE_ANDROID_OS +#include <bionic_tls.h> +// We have a dedicated TLS slot in bionic +inline void setGlThreadSpecific(GLES2Context *value) +{ + ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)value; +} +inline GLES2Context* getGlThreadSpecific() +{ + return (GLES2Context *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]); +} +#else +extern pthread_key_t gGLKey; +inline void setGlThreadSpecific(GLES2Context *value) +{ + pthread_setspecific(gGLKey, value); +} +inline GLES2Context* getGlThreadSpecific() +{ + return static_cast<GLES2Context*>(pthread_getspecific(gGLKey)); +} +#endif + +struct VBO { + unsigned size; + GLenum usage; + void * data; +}; + +struct GLES2Context { + GGLContext rasterizer; + egl_context_t egl; + GGLInterface * iface; // shortcut to &rasterizer.interface + + struct VertexState { + struct VertAttribPointer { + unsigned size; // number of values per vertex + GLenum type; // data type + unsigned stride; // bytes + const void * ptr; +bool normalized : + 1; +bool enabled : + 1; + } attribs [GGL_MAXVERTEXATTRIBS]; + + VBO * vbo, * indices; + std::map<GLuint, VBO *> vbos; + GLuint free; + + Vector4 defaultAttribs [GGL_MAXVERTEXATTRIBS]; + } vert; + + struct TextureState { + GGLTexture * tmus[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS]; + int sampler2tmu[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS]; // sampler2tmu[sampler] is index of tmu, -1 means not used + unsigned active; + std::map<GLuint, GGLTexture *> textures; + GLuint free; // first possible free name + GGLTexture * tex2D, * texCube; // default textures + unsigned unpack; + + void UpdateSampler(GGLInterface * iface, unsigned tmu); + } tex; + + GLES2Context(); + void InitializeTextures(); + void InitializeVertices(); + + ~GLES2Context(); + void UninitializeTextures(); + void UninitializeVertices(); + + static inline GLES2Context* get() { + return getGlThreadSpecific(); + } +}; + +inline egl_context_t* egl_context_t::context(EGLContext ctx) +{ + GLES2Context* const gl = static_cast<GLES2Context*>(ctx); + return static_cast<egl_context_t*>(&gl->egl); +} + +#define GLES2_GET_CONTEXT(ctx) GLES2Context * ctx = GLES2Context::get(); \ + /*puts(__FUNCTION__);*/ +#define GLES2_GET_CONST_CONTEXT(ctx) GLES2Context * ctx = GLES2Context::get(); \ + /*puts(__FUNCTION__);*/ diff --git a/opengl/libagl2/src/shader.cpp b/opengl/libagl2/src/shader.cpp new file mode 100644 index 0000000..076e388 --- /dev/null +++ b/opengl/libagl2/src/shader.cpp @@ -0,0 +1,191 @@ +#include "gles2context.h" + +//#undef LOGD +//#define LOGD(...) + +static inline GLuint s2n(gl_shader * s) +{ + return (GLuint)s ^ 0xaf3c532d; +} + +static inline gl_shader * n2s(GLuint n) +{ + return (gl_shader *)(n ^ 0xaf3c532d); +} + +static inline GLuint p2n(gl_shader_program * p) +{ + return (GLuint)p ^ 0x04dc18f9; +} + +static inline gl_shader_program * n2p(GLuint n) +{ + return (gl_shader_program *)(n ^ 0x04dc18f9); +} + +void glAttachShader(GLuint program, GLuint shader) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderAttach(ctx->iface, n2p(program), n2s(shader)); +} + +void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderAttributeBind(n2p(program), index, name); +// assert(0); +} + +GLuint glCreateShader(GLenum type) +{ + GLES2_GET_CONST_CONTEXT(ctx); + return s2n(ctx->iface->ShaderCreate(ctx->iface, type)); +} + +GLuint glCreateProgram(void) +{ + GLES2_GET_CONST_CONTEXT(ctx); + return p2n(ctx->iface->ShaderProgramCreate(ctx->iface)); +} + +void glCompileShader(GLuint shader) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderCompile(ctx->iface, n2s(shader), NULL, NULL); +} + +void glDeleteProgram(GLuint program) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderProgramDelete(ctx->iface, n2p(program)); +} + +void glDeleteShader(GLuint shader) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderDelete(ctx->iface, n2s(shader)); +} + +void glDetachShader(GLuint program, GLuint shader) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderDetach(ctx->iface, n2p(program), n2s(shader)); +} + +GLint glGetAttribLocation(GLuint program, const GLchar* name) +{ + GLES2_GET_CONST_CONTEXT(ctx); + GLint location = ctx->iface->ShaderAttributeLocation(n2p(program), name); +// LOGD("\n*\n*\n* agl2: glGetAttribLocation program=%u name=%s location=%d \n*\n*", +// program, name, location); + return location; +} + +void glGetProgramiv(GLuint program, GLenum pname, GLint* params) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderProgramGetiv(n2p(program), pname, params); + LOGD("agl2: glGetProgramiv 0x%.4X=%d \n", pname, *params); +} + +void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderProgramGetInfoLog(n2p(program), bufsize, length, infolog); +} + +void glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderGetiv(n2s(shader), pname, params); + LOGD("agl2: glGetShaderiv 0x%.4X=%d \n", pname, *params); +} + +void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderGetInfoLog(n2s(shader), bufsize, length, infolog); +} + +int glGetUniformLocation(GLuint program, const GLchar* name) +{ + GLES2_GET_CONST_CONTEXT(ctx); + return ctx->iface->ShaderUniformLocation(n2p(program), name); +} + +void glLinkProgram(GLuint program) +{ + GLES2_GET_CONST_CONTEXT(ctx); + GLboolean linked = ctx->iface->ShaderProgramLink(n2p(program), NULL); + assert(linked); +} + +void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ShaderSource(n2s(shader), count, string, length); +} + +void glUniform1f(GLint location, GLfloat x) +{ + GLES2_GET_CONST_CONTEXT(ctx); + int sampler = ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, &x, GL_FLOAT); + assert(0 > sampler); // should be assigning to sampler +} + +void glUniform1i(GLint location, GLint x) +{ + GLES2_GET_CONST_CONTEXT(ctx); + const float params[1] = {x}; + int sampler = ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_INT); + if (0 <= sampler) { +// LOGD("\n*\n* agl2: glUniform1i updated sampler=%d tmu=%d location=%d\n*", sampler, x, location); + assert(0 <= x && GGL_MAXCOMBINEDTEXTUREIMAGEUNITS > x); +// LOGD("tmu%u: format=0x%.2X w=%u h=%u levels=%p", x, ctx->tex.tmus[x]->format, +// ctx->tex.tmus[x]->width, ctx->tex.tmus[x]->height, ctx->tex.tmus[x]->format); + ctx->tex.sampler2tmu[sampler] = x; + ctx->tex.UpdateSampler(ctx->iface, x); + } +} + +void glUniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLES2_GET_CONST_CONTEXT(ctx); + const float params[4] = {x, y}; + ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_FLOAT_VEC2); +} + +void glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLES2_GET_CONST_CONTEXT(ctx); + const float params[4] = {x, y, z, w}; +// LOGD("agl2: glUniform4f location=%d %f,%f,%f,%f", location, x, y, z, w); + ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_FLOAT_VEC4); +} + +void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// const gl_shader_program * program = ctx->rasterizer.CurrentProgram; +// if (strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, ").a;")) { +// LOGD("agl2: glUniformMatrix4fv location=%d count=%d transpose=%d", location, count, transpose); +// for (unsigned i = 0; i < 4; i++) +// LOGD("agl2: glUniformMatrix4fv %.2f \t %.2f \t %.2f \t %.2f", value[i * 4 + 0], +// value[i * 4 + 1], value[i * 4 + 2], value[i * 4 + 3]); +// } + ctx->iface->ShaderUniformMatrix(ctx->rasterizer.CurrentProgram, 4, 4, location, count, transpose, value); +// while (true) +// ; +// assert(0); +} + +void glUseProgram(GLuint program) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("\n*\n*\n* agl2: glUseProgram %d \n*\n*\n*", program); + ctx->iface->ShaderUse(ctx->iface, n2p(program)); + ctx->iface->ShaderUniformGetSamplers(n2p(program), ctx->tex.sampler2tmu); + for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) + if (0 <= ctx->tex.sampler2tmu[i]) + ctx->iface->SetSampler(ctx->iface, i, ctx->tex.tmus[ctx->tex.sampler2tmu[i]]); +} diff --git a/opengl/libagl2/src/state.cpp b/opengl/libagl2/src/state.cpp new file mode 100644 index 0000000..22e73fa --- /dev/null +++ b/opengl/libagl2/src/state.cpp @@ -0,0 +1,129 @@ +#include "gles2context.h" + +GLES2Context::GLES2Context() +{ + memset(this, 0, sizeof *this); + + assert((void *)&rasterizer == &rasterizer.interface); + InitializeGGLState(&rasterizer.interface); + iface = &rasterizer.interface; + printf("gl->rasterizer.PickScanLine(%p) = %p \n", &rasterizer.PickScanLine, rasterizer.PickScanLine); + assert(rasterizer.PickRaster); + assert(rasterizer.PickScanLine); + + InitializeTextures(); + InitializeVertices(); +} + +GLES2Context::~GLES2Context() +{ + UninitializeTextures(); + UninitializeVertices(); + UninitializeGGLState(&rasterizer.interface); +} + +void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->BlendColor(ctx->iface, red, green, blue, alpha); +} + +void glBlendEquation( GLenum mode ) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->BlendEquationSeparate(ctx->iface, mode, mode); +} + +void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->BlendEquationSeparate(ctx->iface, modeRGB, modeAlpha); +} + +void glBlendFunc(GLenum sfactor, GLenum dfactor) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->BlendFuncSeparate(ctx->iface, sfactor, dfactor, sfactor, dfactor); +} + +void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->BlendFuncSeparate(ctx->iface, srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void glClear(GLbitfield mask) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->Clear(ctx->iface, mask); +} + +void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ClearColor(ctx->iface, red, green, blue, alpha); +} + +void glClearDepthf(GLclampf depth) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ClearDepthf(ctx->iface, depth); +} + +void glClearStencil(GLint s) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->ClearStencil(ctx->iface, s); +} + +void glCullFace(GLenum mode) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->CullFace(ctx->iface, mode); +} + +void glDisable(GLenum cap) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->EnableDisable(ctx->iface, cap, false); +} + +void glEnable(GLenum cap) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->EnableDisable(ctx->iface, cap, true); +} + +void glFinish(void) +{ + // do nothing +} + +void glFrontFace(GLenum mode) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->iface->FrontFace(ctx->iface, mode); +} + +void glFlush(void) +{ + // do nothing +} + +void glHint(GLenum target, GLenum mode) +{ + // do nothing +} + +void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ +// LOGD("agl2: glScissor not implemented x=%d y=%d width=%d height=%d", x, y, width, height); + //CALL_GL_API(glScissor, x, y, width, height); +} + +void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("agl2: glViewport x=%d y=%d width=%d height=%d", x, y, width, height); + ctx->iface->Viewport(ctx->iface, x, y, width, height); +} diff --git a/opengl/libagl2/src/texture.cpp b/opengl/libagl2/src/texture.cpp new file mode 100644 index 0000000..4de1f16 --- /dev/null +++ b/opengl/libagl2/src/texture.cpp @@ -0,0 +1,534 @@ +#include "gles2context.h" + +//#undef LOGD +//#define LOGD(...) + +#define API_ENTRY +#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0); +#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0; + +static inline GGLTexture * AllocTexture() +{ + GGLTexture * tex = (GGLTexture *)calloc(1, sizeof(GGLTexture)); + tex->minFilter = GGLTexture::GGL_LINEAR; // should be NEAREST_ MIPMAP_LINEAR + tex->magFilter = GGLTexture::GGL_LINEAR; + return tex; +} + +void GLES2Context::InitializeTextures() +{ + tex.textures = std::map<GLuint, GGLTexture *>(); // the entire struct has been zeroed in constructor + tex.tex2D = AllocTexture(); + tex.textures[GL_TEXTURE_2D] = tex.tex2D; + tex.texCube = AllocTexture(); + tex.textures[GL_TEXTURE_CUBE_MAP] = tex.texCube; + for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) { + tex.tmus[i] = NULL; + tex.sampler2tmu[i] = NULL; + } + + tex.active = 0; + + tex.free = max(GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP) + 1; + + tex.tex2D->format = GGL_PIXEL_FORMAT_RGBA_8888; + tex.tex2D->type = GL_TEXTURE_2D; + tex.tex2D->levelCount = 1; + tex.tex2D->wrapS = tex.tex2D->wrapT = GGLTexture::GGL_REPEAT; + tex.tex2D->minFilter = tex.tex2D->magFilter = GGLTexture::GGL_NEAREST; + tex.tex2D->width = tex.tex2D->height = 1; + tex.tex2D->levels = malloc(4); + *(unsigned *)tex.tex2D->levels = 0xff000000; + + + tex.texCube->format = GGL_PIXEL_FORMAT_RGBA_8888; + tex.texCube->type = GL_TEXTURE_CUBE_MAP; + tex.texCube->levelCount = 1; + tex.texCube->wrapS = tex.texCube->wrapT = GGLTexture::GGL_REPEAT; + tex.texCube->minFilter = tex.texCube->magFilter = GGLTexture::GGL_NEAREST; + tex.texCube->width = tex.texCube->height = 1; + tex.texCube->levels = malloc(4 * 6); + static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000, + 0xff00ffff, 0xffffff00, 0xffff00ff + }; + memcpy(tex.texCube->levels, texels, sizeof texels); + + //texture.levelCount = GenerateMipmaps(texture.levels, texture.width, texture.height); + + // static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000, + // 0xff00ffff, 0xffffff00, 0xffff00ff}; + // memcpy(texture.levels[0], texels, sizeof texels); + // texture.format = GGL_PIXEL_FORMAT_RGBA_8888; + // texture.width = texture.height = 1; + //texture.height /= 6; + //texture.type = GL_TEXTURE_CUBE_MAP; + + tex.unpack = 4; +} + +void GLES2Context::TextureState::UpdateSampler(GGLInterface * iface, unsigned tmu) +{ + for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) + if (tmu == sampler2tmu[i]) + iface->SetSampler(iface, i, tmus[tmu]); +} + +void GLES2Context::UninitializeTextures() +{ + for (std::map<GLuint, GGLTexture *>::iterator it = tex.textures.begin(); it != tex.textures.end(); it++) { + if (!it->second) + continue; + free(it->second->levels); + free(it->second); + } +} + +static inline void GetFormatAndBytesPerPixel(const GLenum format, unsigned * bytesPerPixel, + GGLPixelFormat * texFormat) +{ + switch (format) { + case GL_ALPHA: + *texFormat = GGL_PIXEL_FORMAT_A_8; + *bytesPerPixel = 1; + break; + case GL_LUMINANCE: + *texFormat = GGL_PIXEL_FORMAT_L_8; + *bytesPerPixel = 1; + break; + case GL_LUMINANCE_ALPHA: + *texFormat = GGL_PIXEL_FORMAT_LA_88; + *bytesPerPixel = 2; + break; + case GL_RGB: + *texFormat = GGL_PIXEL_FORMAT_RGB_888; + *bytesPerPixel = 3; + break; + case GL_RGBA: + *texFormat = GGL_PIXEL_FORMAT_RGBA_8888; + *bytesPerPixel = 4; + break; + + // internal formats to avoid conversion + case GL_UNSIGNED_SHORT_5_6_5: + *texFormat = GGL_PIXEL_FORMAT_RGB_565; + *bytesPerPixel = 2; + break; + + default: + assert(0); + return; + } +} + +static inline void CopyTexture(char * dst, const char * src, const unsigned bytesPerPixel, + const unsigned sx, const unsigned sy, const unsigned sw, + const unsigned dx, const unsigned dy, const unsigned dw, + const unsigned w, const unsigned h) +{ + const unsigned bpp = bytesPerPixel; + if (dw == sw && dw == w && sx == 0 && dx == 0) + memcpy(dst + dy * dw * bpp, src + sy * sw * bpp, w * h * bpp); + else + for (unsigned y = 0; y < h; y++) + memcpy(dst + ((dy + y) * dw + dx) * bpp, src + ((sy + y) * sw + sx) * bpp, w * bpp); +} + +void glActiveTexture(GLenum texture) +{ + GLES2_GET_CONST_CONTEXT(ctx); + unsigned index = texture - GL_TEXTURE0; + assert(NELEM(ctx->tex.tmus) > index); +// LOGD("agl2: glActiveTexture %u", index); + ctx->tex.active = index; +} + +void glBindTexture(GLenum target, GLuint texture) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("agl2: glBindTexture target=0x%.4X texture=%u active=%u", target, texture, ctx->tex.active); + std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(texture); + GGLTexture * tex = NULL; + if (it != ctx->tex.textures.end()) { + tex = it->second; + if (!tex) { + tex = AllocTexture(); + tex->type = target; + it->second = tex; +// LOGD("agl2: glBindTexture allocTexture"); + } +// else +// LOGD("agl2: glBindTexture bind existing texture"); + assert(target == tex->type); + } else if (0 == texture) { + if (GL_TEXTURE_2D == target) + { + tex = ctx->tex.tex2D; +// LOGD("agl2: glBindTexture bind default tex2D"); + } + else if (GL_TEXTURE_CUBE_MAP == target) + { + tex = ctx->tex.texCube; +// LOGD("agl2: glBindTexture bind default texCube"); + } + else + assert(0); + } else { + if (texture <= ctx->tex.free) + ctx->tex.free = texture + 1; + tex = AllocTexture(); + tex->type = target; + ctx->tex.textures[texture] = tex; +// LOGD("agl2: glBindTexture new texture=%u", texture); + } + ctx->tex.tmus[ctx->tex.active] = tex; +// LOGD("agl2: glBindTexture format=0x%.2X w=%u h=%u levels=%p", tex->format, +// tex->width, tex->height, tex->levels); + ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active); +} + +void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) +{ + CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data); +} + +void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) +{ + CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("agl2: glCopyTexImage2D target=0x%.4X internalformat=0x%.4X", target, internalformat); +// LOGD("x=%d y=%d width=%d height=%d border=%d level=%d ", x, y, width, height, border, level); + assert(0 == border); + assert(0 == level); + unsigned bytesPerPixel = 0; + GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN; + GetFormatAndBytesPerPixel(internalformat, &bytesPerPixel, &texFormat); + + assert(texFormat == ctx->rasterizer.frameSurface.format); +// LOGD("texFormat=0x%.2X bytesPerPixel=%d \n", texFormat, bytesPerPixel); + unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size; + + assert(ctx->tex.tmus[ctx->tex.active]); + assert(y + height <= ctx->rasterizer.frameSurface.height); + assert(x + width <= ctx->rasterizer.frameSurface.width); + GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active]; + tex.width = width; + tex.height = height; + tex.levelCount = 1; + tex.format = texFormat; + switch (target) { + case GL_TEXTURE_2D: + tex.levels = realloc(tex.levels, totalSize); + CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel, + x, y, ctx->rasterizer.frameSurface.width, 0, 0, width, width, height); + break; + default: + assert(0); + return; + } + ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active); +} + +void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + // x, y are src offset + // xoffset and yoffset are dst offset + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("agl2: glCopyTexSubImage2D target=0x%.4X level=%d", target, level); +// LOGD("xoffset=%d yoffset=%d x=%d y=%d width=%d height=%d", xoffset, yoffset, x, y, width, height); + assert(0 == level); + + unsigned bytesPerPixel = 4; + unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size; + + assert(ctx->tex.tmus[ctx->tex.active]); + GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active]; + + assert(tex.format == ctx->rasterizer.frameSurface.format); + assert(GGL_PIXEL_FORMAT_RGBA_8888 == tex.format); + + const unsigned srcWidth = ctx->rasterizer.frameSurface.width; + const unsigned srcHeight = ctx->rasterizer.frameSurface.height; + + assert(x >= 0 && y >= 0); + assert(xoffset >= 0 && yoffset >= 0); + assert(x + width <= srcWidth); + assert(y + height <= srcHeight); + assert(xoffset + width <= tex.width); + assert(yoffset + height <= tex.height); + + switch (target) { + case GL_TEXTURE_2D: + CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel, + x, y, srcWidth, xoffset, yoffset, tex.width, width, height); + break; + default: + assert(0); + return; + } + ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active); +} + +void glDeleteTextures(GLsizei n, const GLuint* textures) +{ + GLES2_GET_CONST_CONTEXT(ctx); + for (unsigned i = 0; i < n; i++) { + std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(textures[i]); + if (it == ctx->tex.textures.end()) + continue; + ctx->tex.free = min(ctx->tex.free, textures[i]); + for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) + if (ctx->tex.tmus[i] == it->second) { + if (GL_TEXTURE_2D == it->second->type) + ctx->tex.tmus[i] = ctx->tex.tex2D; + else if (GL_TEXTURE_CUBE_MAP == it->second->type) + ctx->tex.tmus[i] = ctx->tex.texCube; + else + assert(0); + ctx->tex.UpdateSampler(ctx->iface, i); + } + if (it->second) { + free(it->second->levels); + free(it->second); + } + ctx->tex.textures.erase(it); + } +} + +void glGenTextures(GLsizei n, GLuint* textures) +{ + GLES2_GET_CONST_CONTEXT(ctx); + for (unsigned i = 0; i < n; i++) { + textures[i] = 0; + for (ctx->tex.free; ctx->tex.free < 0xffffffffu; ctx->tex.free++) + if (ctx->tex.textures.find(ctx->tex.free) == ctx->tex.textures.end()) { + ctx->tex.textures[ctx->tex.free] = NULL; + textures[i] = ctx->tex.free; + ctx->tex.free++; + break; + } + assert(textures[i]); + } +} + +void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) +{ + CALL_GL_API(glGetTexParameterfv, target, pname, params); +} +void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) +{ + CALL_GL_API(glGetTexParameteriv, target, pname, params); +} + +GLboolean glIsTexture(GLuint texture) +{ + GLES2_GET_CONST_CONTEXT(ctx); + if (ctx->tex.textures.find(texture) == ctx->tex.textures.end()) + return GL_FALSE; + else + return GL_TRUE; +} + +void glPixelStorei(GLenum pname, GLint param) +{ + GLES2_GET_CONST_CONTEXT(ctx); + assert(GL_UNPACK_ALIGNMENT == pname); + assert(1 == param || 2 == param || 4 == param || 8 == param); +// LOGD("\n*\n* agl2: glPixelStorei not implemented pname=0x%.4X param=%d \n*", pname, param); + ctx->tex.unpack = param; +// CALL_GL_API(glPixelStorei, pname, param); +} +void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("agl2: glTexImage2D internalformat=0x%.4X format=0x%.4X type=0x%.4X \n", internalformat, format, type); +// LOGD("width=%d height=%d border=%d level=%d pixels=%p \n", width, height, border, level, pixels); + switch (type) { + case GL_UNSIGNED_BYTE: + break; + case GL_UNSIGNED_SHORT_5_6_5: + internalformat = format = GL_UNSIGNED_SHORT_5_6_5; + assert(4 == ctx->tex.unpack); + break; + default: + assert(0); + } + assert(internalformat == format); + assert(0 == border); + if (0 != level) { + LOGD("agl2: glTexImage2D level=%d", level); + return; + } + unsigned bytesPerPixel = 0; + GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN; + GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat); + + assert(texFormat && bytesPerPixel); +// LOGD("texFormat=0x%.2X bytesPerPixel=%d active=%u", texFormat, bytesPerPixel, ctx->tex.active); + unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size; + + assert(ctx->tex.tmus[ctx->tex.active]); + + GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active]; + tex.width = width; + tex.height = height; + tex.levelCount = 1; + tex.format = texFormat; + + switch (target) { + case GL_TEXTURE_2D: + assert(GL_TEXTURE_2D == ctx->tex.tmus[ctx->tex.active]->type); + offset = 0; + break; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + assert(GL_TEXTURE_CUBE_MAP == ctx->tex.tmus[ctx->tex.active]->type); + assert(width == height); + offset = (target - GL_TEXTURE_CUBE_MAP_POSITIVE_X) * size; + totalSize = 6 * size; + break; + default: + assert(0); + return; + } + + tex.levels = realloc(tex.levels, totalSize); + if (pixels) + CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, 0, 0, width, width, height); + ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active); +} + +void glTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ +// LOGD("agl2: glTexParameterf target=0x%.4X pname=0x%.4X param=%f", target, pname, param); + glTexParameteri(target, pname, param); +} +void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) +{ + CALL_GL_API(glTexParameterfv, target, pname, params); +} +void glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("alg2: glTexParameteri target=0x%.0X pname=0x%.4X param=0x%.4X", +// target, pname, param); + assert(ctx->tex.tmus[ctx->tex.active]); + assert(target == ctx->tex.tmus[ctx->tex.active]->type); + GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active]; + switch (pname) { + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + GGLTexture::GGLTextureWrap wrap; + switch (param) { + case GL_REPEAT: + wrap = GGLTexture::GGL_REPEAT; + break; + case GL_CLAMP_TO_EDGE: + wrap = GGLTexture::GGL_CLAMP_TO_EDGE; + break; + case GL_MIRRORED_REPEAT: + wrap = GGLTexture::GGL_MIRRORED_REPEAT; + break; + default: + assert(0); + return; + } + if (GL_TEXTURE_WRAP_S == pname) + tex.wrapS = wrap; + else + tex.wrapT = wrap; + break; + case GL_TEXTURE_MIN_FILTER: + switch (param) { + case GL_NEAREST: + tex.minFilter = GGLTexture::GGL_NEAREST; + break; + case GL_LINEAR: + tex.minFilter = GGLTexture::GGL_LINEAR; + break; + case GL_NEAREST_MIPMAP_NEAREST: +// tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: +// tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_LINEAR; + break; + case GL_LINEAR_MIPMAP_NEAREST: +// tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_NEAREST; + break; + case GL_LINEAR_MIPMAP_LINEAR: +// tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_LINEAR; + break; + default: + assert(0); + return; + } + break; + case GL_TEXTURE_MAG_FILTER: + switch (param) { + case GL_NEAREST: + tex.minFilter = GGLTexture::GGL_NEAREST; + break; + case GL_LINEAR: + tex.minFilter = GGLTexture::GGL_LINEAR; + break; + default: + assert(0); + return; + } + break; + default: + assert(0); + return; + } + // implementation restriction + if (tex.magFilter != tex.minFilter) + tex.magFilter = tex.minFilter = GGLTexture::GGL_LINEAR; + ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active); +} +void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) +{ + CALL_GL_API(glTexParameteriv, target, pname, params); +} +void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("agl2: glTexSubImage2D target=0x%.4X level=%d xoffset=%d yoffset=%d width=%d height=%d format=0x%.4X type=0x%.4X pixels=%p", +// target, level, xoffset, yoffset, width, height, format, type, pixels); + assert(0 == level); + assert(target == ctx->tex.tmus[ctx->tex.active]->type); + switch (type) { + case GL_UNSIGNED_BYTE: + break; + case GL_UNSIGNED_SHORT_5_6_5: + format = GL_UNSIGNED_SHORT_5_6_5; + assert(4 == ctx->tex.unpack); + break; + default: + assert(0); + } + GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active]; + GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN; + unsigned bytesPerPixel = 0; + GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat); + assert(texFormat == tex.format); + assert(GL_UNSIGNED_BYTE == type); + switch (target) { + case GL_TEXTURE_2D: + CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, xoffset, + yoffset, tex.width, width, height); + break; + default: + assert(0); + } + ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active); +} diff --git a/opengl/libagl2/src/vertex.cpp b/opengl/libagl2/src/vertex.cpp new file mode 100644 index 0000000..021b82b --- /dev/null +++ b/opengl/libagl2/src/vertex.cpp @@ -0,0 +1,373 @@ +#include "gles2context.h" + +//#undef LOGD +//#define LOGD(...) + +void GLES2Context::InitializeVertices() +{ + vert.vbos = std::map<GLuint, VBO *>(); // the entire struct has been zeroed in constructor + vert.free = 1; + vert.vbo = NULL; + vert.indices = NULL; + for (unsigned i = 0; i < GGL_MAXVERTEXATTRIBS; i++) + vert.defaultAttribs[i] = Vector4(0,0,0,1); +} + +void GLES2Context::UninitializeVertices() +{ + for (std::map<GLuint, VBO *>::iterator it = vert.vbos.begin(); it != vert.vbos.end(); it++) { + if (!it->second) + continue; + free(it->second->data); + free(it->second); + } +} + +static inline void FetchElement(const GLES2Context * ctx, const unsigned index, + const unsigned maxAttrib, VertexInput * elem) +{ + for (unsigned i = 0; i < maxAttrib; i++) { + { + unsigned size = 0; + if (ctx->vert.attribs[i].enabled) { + const char * ptr = (const char *)ctx->vert.attribs[i].ptr; + ptr += ctx->vert.attribs[i].stride * index; + memcpy(elem->attributes + i, ptr, ctx->vert.attribs[i].size * sizeof(float)); + size = ctx->vert.attribs[i].size; +// LOGD("agl2: FetchElement %d attribs size=%d %.2f,%.2f,%.2f,%.2f", i, size, elem->attributes[i].x, +// elem->attributes[i].y, elem->attributes[i].z, elem->attributes[i].w); + } else { +// LOGD("agl2: FetchElement %d default %.2f,%.2f,%.2f,%.2f", i, ctx->vert.defaultAttribs[i].x, +// ctx->vert.defaultAttribs[i].y, ctx->vert.defaultAttribs[i].z, ctx->vert.defaultAttribs[i].w); + } + + switch (size) { + case 0: // fall through + elem->attributes[i].x = ctx->vert.defaultAttribs[i].x; + case 1: // fall through + elem->attributes[i].y = ctx->vert.defaultAttribs[i].y; + case 2: // fall through + elem->attributes[i].z = ctx->vert.defaultAttribs[i].z; + case 3: // fall through + elem->attributes[i].w = ctx->vert.defaultAttribs[i].w; + case 4: + break; + default: + assert(0); + break; + } +// LOGD("agl2: FetchElement %d size=%d %.2f,%.2f,%.2f,%.2f", i, size, elem->attributes[i].x, +// elem->attributes[i].y, elem->attributes[i].z, elem->attributes[i].w); + } + } +} + +template<typename IndexT> static void DrawElementsTriangles(const GLES2Context * ctx, + const unsigned count, const IndexT * indices, const unsigned maxAttrib) +{ + VertexInput v[3]; + if (ctx->vert.indices) + indices = (IndexT *)((char *)ctx->vert.indices->data + (long)indices); + for (unsigned i = 0; i < count; i += 3) { + for (unsigned j = 0; j < 3; j++) + FetchElement(ctx, indices[i + j], maxAttrib, v + j); + ctx->iface->DrawTriangle(ctx->iface, v, v + 1, v + 2); + } +} + +static void DrawArraysTriangles(const GLES2Context * ctx, const unsigned first, + const unsigned count, const unsigned maxAttrib) +{ +// LOGD("agl: DrawArraysTriangles=%p", DrawArraysTriangles); + VertexInput v[3]; + for (unsigned i = 2; i < count; i+=3) { + // TODO: fix order + FetchElement(ctx, first + i - 2, maxAttrib, v + 0); + FetchElement(ctx, first + i - 1, maxAttrib, v + 1); + FetchElement(ctx, first + i - 0, maxAttrib, v + 2); + ctx->iface->DrawTriangle(ctx->iface, v + 0, v + 1, v + 2); + } +// LOGD("agl: DrawArraysTriangles end"); +} + +template<typename IndexT> static void DrawElementsTriangleStrip(const GLES2Context * ctx, + const unsigned count, const IndexT * indices, const unsigned maxAttrib) +{ + VertexInput v[3]; + if (ctx->vert.indices) + indices = (IndexT *)((char *)ctx->vert.indices->data + (long)indices); + +// LOGD("agl2: DrawElementsTriangleStrip"); +// for (unsigned i = 0; i < count; i++) +// LOGD("indices[%d] = %d", i, indices[i]); + + FetchElement(ctx, indices[0], maxAttrib, v + 0); + FetchElement(ctx, indices[1], maxAttrib, v + 1); + for (unsigned i = 2; i < count; i ++) { + FetchElement(ctx, indices[i], maxAttrib, v + i % 3); + ctx->iface->DrawTriangle(ctx->iface, v + (i - 2) % 3, v + (i - 1) % 3 , v + (i + 0) % 3); + } + +// for (unsigned i = 2; i < count; i++) { +// FetchElement(ctx, indices[i - 2], maxAttrib, v + 0); +// FetchElement(ctx, indices[i - 1], maxAttrib, v + 1); +// FetchElement(ctx, indices[i - 0], maxAttrib, v + 2); +// ctx->iface->DrawTriangle(ctx->iface, v + 0, v + 1, v + 2); +// } +} + +static void DrawArraysTriangleStrip(const GLES2Context * ctx, const unsigned first, + const unsigned count, const unsigned maxAttrib) +{ + VertexInput v[3]; + FetchElement(ctx, first, maxAttrib, v + 0); + FetchElement(ctx, first + 1, maxAttrib, v + 1); + for (unsigned i = 2; i < count; i++) { + // TODO: fix order + FetchElement(ctx, first + i, maxAttrib, v + i % 3); + ctx->iface->DrawTriangle(ctx->iface, v + (i - 2) % 3, v + (i - 1) % 3 , v + (i + 0) % 3); + } +} + +void glBindBuffer(GLenum target, GLuint buffer) +{ + GLES2_GET_CONST_CONTEXT(ctx); + VBO * vbo = NULL; + if (0 != buffer) { + std::map<GLuint, VBO *>::iterator it = ctx->vert.vbos.find(buffer); + if (it != ctx->vert.vbos.end()) { + vbo = it->second; + if (!vbo) + vbo = (VBO *)calloc(1, sizeof(VBO)); + it->second = vbo; + } else + assert(0); + } + if (GL_ARRAY_BUFFER == target) + ctx->vert.vbo = vbo; + else if (GL_ELEMENT_ARRAY_BUFFER == target) + ctx->vert.indices = vbo; + else + assert(0); + assert(vbo || buffer == 0); +// LOGD("\n*\n glBindBuffer 0x%.4X=%d ", target, buffer); +} + +void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +{ + GLES2_GET_CONST_CONTEXT(ctx); + if (GL_ARRAY_BUFFER == target) { + assert(ctx->vert.vbo); + ctx->vert.vbo->data = realloc(ctx->vert.vbo->data, size); + ctx->vert.vbo->size = size; + ctx->vert.vbo->usage = usage; + if (data) + memcpy(ctx->vert.vbo->data, data, size); + } else if (GL_ELEMENT_ARRAY_BUFFER == target) { + assert(ctx->vert.indices); + ctx->vert.indices->data = realloc(ctx->vert.indices->data, size); + ctx->vert.indices->size = size; + ctx->vert.indices->usage = usage; + if (data) + memcpy(ctx->vert.indices->data, data, size); + } else + assert(0); +// LOGD("\n*\n glBufferData target=0x%.4X size=%u data=%p usage=0x%.4X \n", +// target, size, data, usage); +} + +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +{ + GLES2_GET_CONST_CONTEXT(ctx); + if (GL_ARRAY_BUFFER == target) + { + assert(ctx->vert.vbo); + assert(0 <= offset); + assert(0 <= size); + assert(offset + size <= ctx->vert.vbo->size); + memcpy((char *)ctx->vert.vbo->data + offset, data, size); + } + else + assert(0); +} + +void glDeleteBuffers(GLsizei n, const GLuint* buffers) +{ + GLES2_GET_CONST_CONTEXT(ctx); + for (unsigned i = 0; i < n; i++) { + std::map<GLuint, VBO*>::iterator it = ctx->vert.vbos.find(buffers[i]); + if (it == ctx->vert.vbos.end()) + continue; + ctx->vert.free = min(ctx->vert.free, buffers[i]); + if (it->second == ctx->vert.vbo) + ctx->vert.vbo = NULL; + else if (it->second == ctx->vert.indices) + ctx->vert.indices = NULL; + if (it->second) { + free(it->second->data); + free(it->second); + } + } +} + +void glDisableVertexAttribArray(GLuint index) +{ + GLES2_GET_CONST_CONTEXT(ctx); + assert(GGL_MAXVERTEXATTRIBS > index); + ctx->vert.attribs[index].enabled = false; +} + +void glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("agl2: glDrawArrays=%p", glDrawArrays); + assert(ctx->rasterizer.CurrentProgram); + assert(0 <= first); + int maxAttrib = -1; + ctx->iface->ShaderProgramGetiv(ctx->rasterizer.CurrentProgram, GL_ACTIVE_ATTRIBUTES, &maxAttrib); + assert(0 <= maxAttrib && GGL_MAXVERTEXATTRIBS >= maxAttrib); + switch (mode) { + case GL_TRIANGLE_STRIP: + DrawArraysTriangleStrip(ctx, first, count, maxAttrib); + break; + case GL_TRIANGLES: + DrawArraysTriangles(ctx, first, count, maxAttrib); + break; + default: + LOGE("agl2: glDrawArrays unsupported mode: 0x%.4X \n", mode); + assert(0); + break; + } +// LOGD("agl2: glDrawArrays end"); +} + +void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +{ + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("agl2: glDrawElements=%p mode=0x%.4X count=%d type=0x%.4X indices=%p", +// glDrawElements, mode, count, type, indices); + if (!ctx->rasterizer.CurrentProgram) + return; + + int maxAttrib = -1; + ctx->iface->ShaderProgramGetiv(ctx->rasterizer.CurrentProgram, GL_ACTIVE_ATTRIBUTES, &maxAttrib); + assert(0 <= maxAttrib && GGL_MAXVERTEXATTRIBS >= maxAttrib); +// LOGD("agl2: glDrawElements mode=0x%.4X type=0x%.4X count=%d program=%p indices=%p \n", +// mode, type, count, ctx->rasterizer.CurrentProgram, indices); + switch (mode) { + case GL_TRIANGLES: + if (GL_UNSIGNED_SHORT == type) + DrawElementsTriangles<unsigned short>(ctx, count, (unsigned short *)indices, maxAttrib); + else + assert(0); + break; + case GL_TRIANGLE_STRIP: + if (GL_UNSIGNED_SHORT == type) + DrawElementsTriangleStrip<unsigned short>(ctx, count, (unsigned short *)indices, maxAttrib); + else + assert(0); + break; + default: + assert(0); + } +// LOGD("agl2: glDrawElements end"); +} + +void glEnableVertexAttribArray(GLuint index) +{ + GLES2_GET_CONST_CONTEXT(ctx); + ctx->vert.attribs[index].enabled = true; +// LOGD("agl2: glEnableVertexAttribArray %d \n", index); +} + +void glGenBuffers(GLsizei n, GLuint* buffers) +{ + GLES2_GET_CONST_CONTEXT(ctx); + for (unsigned i = 0; i < n; i++) { + buffers[i] = 0; + for (ctx->vert.free; ctx->vert.free < 0xffffffffu; ctx->vert.free++) { + if (ctx->vert.vbos.find(ctx->vert.free) == ctx->vert.vbos.end()) { + ctx->vert.vbos[ctx->vert.free] = NULL; + buffers[i] = ctx->vert.free; +// LOGD("glGenBuffers %d \n", buffers[i]); + ctx->vert.free++; + break; + } + } + assert(buffers[i]); + } +} + +void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, + GLsizei stride, const GLvoid* ptr) +{ + GLES2_GET_CONST_CONTEXT(ctx); + assert(GL_FLOAT == type); + assert(0 < size && 4 >= size); + ctx->vert.attribs[index].size = size; + ctx->vert.attribs[index].type = type; + ctx->vert.attribs[index].normalized = normalized; + if (0 == stride) + ctx->vert.attribs[index].stride = size * sizeof(float); + else if (stride > 0) + ctx->vert.attribs[index].stride = stride; + else + assert(0); +// LOGD("\n*\n*\n* agl2: glVertexAttribPointer program=%u index=%d size=%d stride=%d ptr=%p \n*\n*", +// unsigned(ctx->rasterizer.CurrentProgram) ^ 0x04dc18f9, index, size, stride, ptr); + if (ctx->vert.vbo) + ctx->vert.attribs[index].ptr = (char *)ctx->vert.vbo->data + (long)ptr; + else + ctx->vert.attribs[index].ptr = ptr; +// const float * attrib = (const float *)ctx->vert.attribs[index].ptr; +// for (unsigned i = 0; i < 3; i++) +// if (3 == size) +// LOGD("%.2f %.2f %.2f", attrib[i * 3 + 0], attrib[i * 3 + 1], attrib[i * 3 + 2]); +// else if (2 == size) +// LOGD("%.2f %.2f", attrib[i * 3 + 0], attrib[i * 3 + 1]); + +} + +void glVertexAttrib1f(GLuint indx, GLfloat x) +{ + glVertexAttrib4f(indx, x,0,0,1); +} + +void glVertexAttrib1fv(GLuint indx, const GLfloat* values) +{ + glVertexAttrib4f(indx, values[0],0,0,1); +} + +void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) +{ + glVertexAttrib4f(indx, x,y,0,1); +} + +void glVertexAttrib2fv(GLuint indx, const GLfloat* values) +{ + glVertexAttrib4f(indx, values[0],values[1],0,1); +} + +void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) +{ + glVertexAttrib4f(indx, x,y,z,1); +} + +void glVertexAttrib3fv(GLuint indx, const GLfloat* values) +{ + glVertexAttrib4f(indx, values[0],values[1],values[2],1); +} + +void glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + assert(GGL_MAXVERTEXATTRIBS > indx); + GLES2_GET_CONST_CONTEXT(ctx); +// LOGD("\n*\n*\n agl2: glVertexAttrib4f %d %.2f,%.2f,%.2f,%.2f \n*\n*", indx, x, y, z, w); + ctx->vert.defaultAttribs[indx] = Vector4(x,y,z,w); + assert(0); +} + +void glVertexAttrib4fv(GLuint indx, const GLfloat* values) +{ + glVertexAttrib4f(indx, values[0], values[1], values[2], values[3]); +} diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index c8041fc..7d72729 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -13,11 +13,11 @@ LOCAL_SRC_FILES:= \ EGL/hooks.cpp \ EGL/Loader.cpp \ # - -LOCAL_SHARED_LIBRARIES += libcutils libutils +LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite liblzf +LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport LOCAL_LDLIBS := -lpthread -ldl LOCAL_MODULE:= libEGL - +LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL # needed on sim build because of weird logging issues ifeq ($(TARGET_SIMULATOR),true) else @@ -164,3 +164,6 @@ LOCAL_LDLIBS := -lpthread -ldl LOCAL_MODULE:= libETC1 include $(BUILD_SHARED_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) + diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 747c829..2502f15 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -30,6 +30,7 @@ #include "egl_impl.h" #include "Loader.h" +#include "glesv2dbg.h" // ---------------------------------------------------------------------------- namespace android { @@ -114,6 +115,7 @@ Loader::Loader() Loader::~Loader() { + StopDebugServer(); } const char* Loader::getTag(int dpy, int impl) diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index e13af1c..a53b375 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -45,6 +45,7 @@ #include "hooks.h" #include "egl_impl.h" #include "Loader.h" +#include "glesv2dbg.h" #define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r) @@ -71,25 +72,78 @@ static char const * const gExtensionString = // ---------------------------------------------------------------------------- -class egl_object_t { - static SortedVector<egl_object_t*> sObjects; - static Mutex sLock; +class egl_object_t; +struct egl_display_t; +static egl_display_t* get_display(EGLDisplay dpy); + +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; + } +}; + +struct egl_display_t { + enum { NOT_INITIALIZED, INITIALIZED, TERMINATED }; + + struct strings_t { + char const * vendor; + char const * version; + char const * clientApi; + char const * extensions; + }; + + struct DisplayImpl { + DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0), + state(NOT_INITIALIZED), numConfigs(0) { } + EGLDisplay dpy; + EGLConfig* config; + EGLint state; + EGLint numConfigs; + strings_t queryString; + }; + uint32_t magic; + DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS]; + EGLint numTotalConfigs; + egl_config_t* configs; + uint32_t refs; + Mutex lock; + + SortedVector<egl_object_t*> objects; + + egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0) { } + ~egl_display_t() { magic = 0; } + inline bool isReady() const { return (refs > 0); } + inline bool isValid() const { return magic == '_dpy'; } + inline bool isAlive() const { return isValid(); } +}; + +class egl_object_t { + egl_display_t *display; volatile int32_t terminated; mutable volatile int32_t count; public: - egl_object_t() : terminated(0), count(1) { - Mutex::Autolock _l(sLock); - sObjects.add(this); + egl_object_t(EGLDisplay dpy) : display(get_display(dpy)), terminated(0), count(1) { + Mutex::Autolock _l(display->lock); + display->objects.add(this); } inline bool isAlive() const { return !terminated; } private: bool get() { - Mutex::Autolock _l(sLock); - if (egl_object_t::sObjects.indexOf(this) >= 0) { + Mutex::Autolock _l(display->lock); + if (display->objects.indexOf(this) >= 0) { android_atomic_inc(&count); return true; } @@ -97,9 +151,9 @@ private: } bool put() { - Mutex::Autolock _l(sLock); + Mutex::Autolock _l(display->lock); if (android_atomic_dec(&count) == 1) { - sObjects.remove(this); + display->objects.remove(this); return true; } return false; @@ -146,65 +200,13 @@ public: }; }; -SortedVector<egl_object_t*> egl_object_t::sObjects; -Mutex egl_object_t::sLock; - - -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; - } -}; - -struct egl_display_t { - enum { NOT_INITIALIZED, INITIALIZED, TERMINATED }; - - struct strings_t { - char const * vendor; - char const * version; - char const * clientApi; - char const * extensions; - }; - - struct DisplayImpl { - DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0), - state(NOT_INITIALIZED), numConfigs(0) { } - EGLDisplay dpy; - EGLConfig* config; - EGLint state; - EGLint numConfigs; - strings_t queryString; - }; - - uint32_t magic; - DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS]; - EGLint numTotalConfigs; - egl_config_t* configs; - uint32_t refs; - Mutex lock; - - egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0) { } - ~egl_display_t() { magic = 0; } - inline bool isValid() const { return magic == '_dpy'; } - inline bool isAlive() const { return isValid(); } -}; - struct egl_surface_t : public egl_object_t { 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) - : dpy(dpy), surface(surface), config(config), win(win), impl(impl), cnx(cnx) { + : egl_object_t(dpy), dpy(dpy), surface(surface), config(config), win(win), impl(impl), cnx(cnx) { } ~egl_surface_t() { } @@ -222,10 +224,16 @@ struct egl_context_t : public egl_object_t egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, int impl, egl_connection_t const* cnx, int version) - : dpy(dpy), context(context), config(config), read(0), draw(0), impl(impl), - cnx(cnx), version(version) + : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0), + impl(impl), cnx(cnx), version(version), dbg(NULL) { } + ~egl_context_t() + { + if (dbg) + DestroyDbgContext(dbg); + dbg = NULL; + } EGLDisplay dpy; EGLContext context; EGLConfig config; @@ -234,6 +242,7 @@ struct egl_context_t : public egl_object_t int impl; egl_connection_t const* cnx; int version; + DbgContext * dbg; }; struct egl_image_t : public egl_object_t @@ -241,7 +250,7 @@ struct egl_image_t : public egl_object_t typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref; egl_image_t(EGLDisplay dpy, EGLContext context) - : dpy(dpy), context(context) + : egl_object_t(dpy), dpy(dpy), context(context) { memset(images, 0, sizeof(images)); } @@ -255,7 +264,7 @@ struct egl_sync_t : public egl_object_t typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref; egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync) - : dpy(dpy), context(context), sync(sync) + : egl_object_t(dpy), dpy(dpy), context(context), sync(sync) { } EGLDisplay dpy; @@ -296,9 +305,9 @@ EGLAPI pthread_key_t gGLTraceKey = -1; // ---------------------------------------------------------------------------- -static int gEGLTraceLevel; +static int gEGLTraceLevel, gEGLDebugLevel; static int gEGLApplicationTraceLevel; -extern EGLAPI gl_hooks_t gHooksTrace; +extern EGLAPI gl_hooks_t gHooksTrace, gHooksDebug; static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) { pthread_setspecific(gGLTraceKey, value); @@ -314,12 +323,37 @@ static void initEglTraceLevel() { int propertyLevel = atoi(value); int applicationLevel = gEGLApplicationTraceLevel; gEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel; + + property_get("debug.egl.debug_proc", value, ""); + long pid = getpid(); + char procPath[128] = {}; + sprintf(procPath, "/proc/%ld/cmdline", pid); + FILE * file = fopen(procPath, "r"); + if (file) + { + char cmdline[256] = {}; + if (fgets(cmdline, sizeof(cmdline) - 1, file)) + { + if (!strcmp(value, cmdline)) + gEGLDebugLevel = 1; + } + fclose(file); + } + + if (gEGLDebugLevel > 0) + { + property_get("debug.egl.debug_port", value, "5039"); + StartDebugServer(atoi(value)); + } } static void setGLHooksThreadSpecific(gl_hooks_t const *value) { if (gEGLTraceLevel > 0) { setGlTraceThreadSpecific(value); setGlThreadSpecific(&gHooksTrace); + } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) { + setGlTraceThreadSpecific(value); + setGlThreadSpecific(&gHooksDebug); } else { setGlThreadSpecific(value); } @@ -561,6 +595,11 @@ egl_context_t* get_context(EGLContext context) { return egl_to_native_cast<egl_context_t>(context); } +DbgContext * getDbgContextThreadSpecific() +{ + return get_context(getContext())->dbg; +} + static inline egl_image_t* get_image(EGLImageKHR image) { return egl_to_native_cast<egl_image_t>(image); @@ -571,12 +610,22 @@ egl_sync_t* get_sync(EGLSyncKHR sync) { return egl_to_native_cast<egl_sync_t>(sync); } +static inline +egl_display_t* validate_display(EGLDisplay dpy) +{ + egl_display_t * const dp = get_display(dpy); + if (!dp) return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL); + if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL); + + return dp; +} + static egl_connection_t* validate_display_config( EGLDisplay dpy, EGLConfig config, egl_display_t const*& dp) { - dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL); + 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); @@ -590,9 +639,9 @@ static egl_connection_t* validate_display_config( static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx) { - if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - if (!get_display(dpy)->isAlive()) + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + if (!dp->isAlive()) return setError(EGL_BAD_DISPLAY, EGL_FALSE); if (!get_context(ctx)->isAlive()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); @@ -601,9 +650,9 @@ static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx) static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface) { - if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - if (!get_display(dpy)->isAlive()) + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + if (!dp->isAlive()) return setError(EGL_BAD_DISPLAY, EGL_FALSE); if (!get_surface(surface)->isAlive()) return setError(EGL_BAD_SURFACE, EGL_FALSE); @@ -923,8 +972,8 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, { clearError(); - egl_display_t const * const dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; GLint numConfigs = dp->numTotalConfigs; if (!configs) { @@ -949,8 +998,8 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, { clearError(); - egl_display_t const * const dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; if (num_config==0) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); @@ -1168,12 +1217,14 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, surface)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t * const s = get_surface(surface); EGLBoolean result = s->cnx->egl.eglDestroySurface( @@ -1192,12 +1243,14 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, surface)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); EGLBoolean result(EGL_TRUE); @@ -1260,12 +1313,14 @@ EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + ContextRef _c(ctx); if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); if (!validate_display_context(dpy, ctx)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_context_t * const c = get_context(ctx); EGLBoolean result = c->cnx->egl.eglDestroyContext( dp->disp[c->impl].dpy, c->context); @@ -1301,14 +1356,23 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, { clearError(); + egl_display_t const * const dp = get_display(dpy); + if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + + /* If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not + EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is + a valid but uninitialized display. */ + if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) || + (draw != EGL_NO_SURFACE) ) { + if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE); + } + // get a reference to the object passed in ContextRef _c(ctx); SurfaceRef _d(draw); SurfaceRef _r(read); - // validate the display and the context (if not EGL_NO_CONTEXT) - egl_display_t const * const dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + // validate the context (if not EGL_NO_CONTEXT) if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) { // EGL_NO_CONTEXT is valid return EGL_FALSE; @@ -1378,6 +1442,8 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, loseCurrent(cur_c); if (ctx != EGL_NO_CONTEXT) { + if (!c->dbg && gEGLDebugLevel > 0) + c->dbg = CreateDbgContext(c->version, c->cnx->hooks[c->version]); setGLHooksThreadSpecific(c->cnx->hooks[c->version]); setContext(ctx); _c.acquire(); @@ -1399,13 +1465,15 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + ContextRef _c(ctx); if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); if (!validate_display_context(dpy, ctx)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_context_t * const c = get_context(ctx); EGLBoolean result(EGL_TRUE); @@ -1607,7 +1675,7 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] = cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] = #if EGL_TRACE - gHooksTrace.ext.extensions[slot] = + gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] = #endif cnx->egl.eglGetProcAddress(procname); } @@ -1635,14 +1703,20 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) { + EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw); + if (gEGLDebugLevel > 0) + Debug_eglSwapBuffers(dpy, draw); + clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(draw); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, draw)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(draw); return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface); } @@ -1652,12 +1726,14 @@ EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, surface)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); return s->cnx->egl.eglCopyBuffers( dp->disp[s->impl].dpy, s->surface, target); @@ -1667,7 +1743,9 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) { clearError(); - egl_display_t const * const dp = get_display(dpy); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return (const char *) NULL; + switch (name) { case EGL_VENDOR: return gVendorString; @@ -1691,12 +1769,14 @@ EGLBoolean eglSurfaceAttrib( { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, surface)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglSurfaceAttrib) { return s->cnx->egl.eglSurfaceAttrib( @@ -1710,12 +1790,14 @@ EGLBoolean eglBindTexImage( { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, surface)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglBindTexImage) { return s->cnx->egl.eglBindTexImage( @@ -1729,12 +1811,14 @@ EGLBoolean eglReleaseTexImage( { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, surface)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglReleaseTexImage) { return s->cnx->egl.eglReleaseTexImage( @@ -1747,8 +1831,8 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { clearError(); - egl_display_t * const dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; EGLBoolean res = EGL_TRUE; for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { @@ -1886,13 +1970,15 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, surface)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglLockSurfaceKHR) { @@ -1906,13 +1992,15 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(surface); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, surface)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglUnlockSurfaceKHR) { @@ -1927,12 +2015,14 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_NO_IMAGE_KHR; + if (ctx != EGL_NO_CONTEXT) { ContextRef _c(ctx); if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); if (!validate_display_context(dpy, ctx)) return EGL_NO_IMAGE_KHR; - egl_display_t const * const dp = get_display(dpy); 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( @@ -1945,10 +2035,6 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, return (EGLImageKHR)result; } else { // EGL_NO_CONTEXT is a valid parameter - egl_display_t const * const dp = get_display(dpy); - if (dp == 0) { - return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR); - } /* 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 @@ -2000,35 +2086,33 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { clearError(); - egl_display_t const * const dp = get_display(dpy); - if (dp == 0) { - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - } - - ImageRef _i(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; - } - } - } - } - } - if (!success) - return EGL_FALSE; - - _i.terminate(); - - return EGL_TRUE; + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + ImageRef _i(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; + } + } + } + } + } + if (!success) + return EGL_FALSE; + + _i.terminate(); + + return EGL_TRUE; } // ---------------------------------------------------------------------------- @@ -2040,12 +2124,14 @@ EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_l { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_NO_SYNC_KHR; + EGLContext ctx = eglGetCurrentContext(); ContextRef _c(ctx); if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR); if (!validate_display_context(dpy, ctx)) return EGL_NO_SYNC_KHR; - egl_display_t const * const dp = get_display(dpy); egl_context_t * const c = get_context(ctx); EGLSyncKHR result = EGL_NO_SYNC_KHR; if (c->cnx->egl.eglCreateSyncKHR) { @@ -2062,10 +2148,8 @@ EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { clearError(); - egl_display_t const * const dp = get_display(dpy); - if (dp == 0) { - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - } + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; SyncRef _s(sync); if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); @@ -2092,10 +2176,8 @@ EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTi { clearError(); - egl_display_t const * const dp = get_display(dpy); - if (dp == 0) { - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - } + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; SyncRef _s(sync); if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); @@ -2121,10 +2203,8 @@ EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute { clearError(); - egl_display_t const * const dp = get_display(dpy); - if (dp == 0) { - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - } + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; SyncRef _s(sync); if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); @@ -2155,12 +2235,14 @@ EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, { clearError(); + egl_display_t const * const dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + SurfaceRef _s(draw); if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); if (!validate_display_surface(dpy, draw)) return EGL_FALSE; - egl_display_t const * const dp = get_display(dpy); egl_surface_t const * const s = get_surface(draw); if (s->cnx->egl.eglSetSwapRectangleANDROID) { return s->cnx->egl.eglSetSwapRectangleANDROID( diff --git a/opengl/libs/EGL/trace.cpp b/opengl/libs/EGL/trace.cpp index d3e96ba..f3e101b 100644 --- a/opengl/libs/EGL/trace.cpp +++ b/opengl/libs/EGL/trace.cpp @@ -325,7 +325,7 @@ static void Tracing_ ## _api _args { \ #define TRACE_GL(_type, _api, _args, _argList, ...) \ static _type Tracing_ ## _api _args { \ - TraceGL(#_api, __VA_ARGS__); \ + TraceGL(#_api, __VA_ARGS__); \ gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \ return _c->_api _argList; \ } @@ -333,11 +333,11 @@ static _type Tracing_ ## _api _args { \ extern "C" { #include "../trace.in" } + #undef TRACE_GL_VOID #undef TRACE_GL #define GL_ENTRY(_r, _api, ...) Tracing_ ## _api, - EGLAPI gl_hooks_t gHooksTrace = { { #include "entries.in" @@ -348,6 +348,48 @@ EGLAPI gl_hooks_t gHooksTrace = { }; #undef GL_ENTRY + +#undef TRACE_GL_VOID +#undef TRACE_GL + +// define the ES 1.0 Debug_gl* functions as Tracing_gl functions +#define TRACE_GL_VOID(_api, _args, _argList, ...) \ +static void Debug_ ## _api _args { \ + TraceGL(#_api, __VA_ARGS__); \ + gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \ + _c->_api _argList; \ +} + +#define TRACE_GL(_type, _api, _args, _argList, ...) \ +static _type Debug_ ## _api _args { \ + TraceGL(#_api, __VA_ARGS__); \ + gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \ + return _c->_api _argList; \ +} + +extern "C" { +#include "../debug.in" +} + +#undef TRACE_GL_VOID +#undef TRACE_GL + +// declare all Debug_gl* functions +#define GL_ENTRY(_r, _api, ...) _r Debug_##_api ( __VA_ARGS__ ); +#include "glesv2dbg_functions.h" +#undef GL_ENTRY + +#define GL_ENTRY(_r, _api, ...) Debug_ ## _api, +EGLAPI gl_hooks_t gHooksDebug = { + { + #include "entries.in" + }, + { + {0} + } +}; +#undef GL_ENTRY + // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk new file mode 100644 index 0000000..fc40799 --- /dev/null +++ b/opengl/libs/GLES2_dbg/Android.mk @@ -0,0 +1,46 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + src/api.cpp \ + src/caller.cpp \ + src/dbgcontext.cpp \ + src/debugger_message.pb.cpp \ + src/egl.cpp \ + src/server.cpp \ + src/vertex.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../ \ + external/stlport/stlport \ + external/protobuf/src \ + external \ + bionic + +#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG +LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI + +ifeq ($(TARGET_ARCH),arm) + LOCAL_CFLAGS += -fstrict-aliasing +endif + +ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true) + LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER +endif + +ifneq ($(TARGET_SIMULATOR),true) + # we need to access the private Bionic header <bionic_tls.h> + # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER + # behavior from the bionic Android.mk file + ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true) + LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER + endif + LOCAL_C_INCLUDES += bionic/libc/private +endif + +LOCAL_MODULE:= libGLESv2_dbg +LOCAL_MODULE_TAGS := optional + +include $(BUILD_STATIC_LIBRARY) diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py new file mode 100755 index 0000000..66c110f --- /dev/null +++ b/opengl/libs/GLES2_dbg/generate_api_cpp.py @@ -0,0 +1,206 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# +# 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. +# + +import os +import sys + +def RemoveAnnotation(line): + if line.find(":") >= 0: + annotation = line[line.find(":"): line.find(" ", line.find(":"))] + return line.replace(annotation, "*") + else: + return line + +def generate_api(lines): + externs = [] + i = 0 + # these have been hand written + skipFunctions = ["glReadPixels", "glDrawArrays", "glDrawElements"] + + # these have an EXTEND_Debug_* macro for getting data + extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glShaderSource", +"glTexImage2D", "glTexSubImage2D"] + + # these also needs to be forwarded to DbgContext + contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray", +"glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",] + + for line in lines: + if line.find("API_ENTRY(") >= 0: # a function prototype + returnType = line[0: line.find(" API_ENTRY(")] + functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name + parameterList = line[line.find(")(") + 2: line.find(") {")] + + #if line.find("*") >= 0: + # extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList) + # externs.append(extern) + # continue + + if functionName in skipFunctions: + sys.stderr.write("!\n! skipping function '%s'\n!\n" % (functionName)) + continue + + parameters = parameterList.split(',') + paramIndex = 0 + if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer + if not functionName in extendFunctions: + # add function to list of functions that should be hand written, but generate code anyways + extern = "%s Debug_%s(%s);" % (returnType, functionName, RemoveAnnotation(parameterList)) + sys.stderr.write("%s should be hand written\n" % (extern)) + print "// FIXME: this function has pointers, it should be hand written" + externs.append(extern) + + print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList)) + print " glesv2debugger::Message msg;" + + if parameterList == "void": + parameters = [] + arguments = "" + paramNames = [] + inout = "" + getData = "" + + callerMembers = "" + setCallerMembers = "" + setMsgParameters = "" + + for parameter in parameters: + const = parameter.find("const") + parameter = parameter.replace("const", "") + parameter = parameter.strip() + paramType = parameter.split(' ')[0] + paramName = parameter.split(' ')[1] + annotation = "" + arguments += paramName + if parameter.find(":") >= 0: # has annotation + assert inout == "" # only one parameter should be annotated + sys.stderr.write("%s is annotated: %s \n" % (functionName, paramType)) + inout = paramType.split(":")[2] + annotation = paramType.split(":")[1] + paramType = paramType.split(":")[0] + count = 1 + countArg = "" + if annotation.find("*") >= 0: # [1,n] * param + count = int(annotation.split("*")[0]) + countArg = annotation.split("*")[1] + assert countArg in paramNames + elif annotation in paramNames: + count = 1 + countArg = annotation + elif annotation == "GLstring": + annotation = "strlen(%s)" % (paramName) + else: + count = int(annotation) + + setMsgParameters += " msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName) + if paramType.find("void") >= 0: + getData += " msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(char));" % (paramName, annotation) + else: + getData += " msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(%s));" % (paramName, annotation, paramType) + paramType += "*" + else: + if paramType == "GLfloat" or paramType == "GLclampf" or paramType.find("*") >= 0: + setMsgParameters += " msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName) + else: + setMsgParameters += " msg.set_arg%d(%s);\n" % (paramIndex, paramName) + if paramIndex < len(parameters) - 1: + arguments += ', ' + if const >= 0: + paramType = "const " + paramType + paramNames.append(paramName) + paramIndex += 1 + callerMembers += " %s %s;\n" % (paramType, paramName) + setCallerMembers += " caller.%s = %s;\n" % (paramName, paramName) + + print " struct : public FunctionCall {" + print callerMembers + print " const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {" + if inout in ["out", "inout"]: # get timing excluding output data copy + print " nsecs_t c0 = systemTime(timeMode);" + if returnType == "void": + print " _c->%s(%s);" % (functionName, arguments) + else: + print " const int * ret = reinterpret_cast<const int *>(_c->%s(%s));" % (functionName, arguments) + print " msg.set_ret(ToInt(ret));" + if inout in ["out", "inout"]: + print " msg.set_time((systemTime(timeMode) - c0) * 1e-6f);" + print " " + getData + if functionName in contextFunctions: + print " getDbgContextThreadSpecific()->%s(%s);" % (functionName, arguments) + if returnType == "void": + print " return 0;" + else: + print " return ret;" + print """ } + } caller;""" + print setCallerMembers + print setMsgParameters + + if line.find("*") >= 0 or line.find(":") >= 0: + print " // FIXME: check for pointer usage" + if inout in ["in", "inout"]: + print getData + if functionName in extendFunctions: + print " EXTEND_Debug_%s;" % (functionName) + print " int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_%s);"\ + % (functionName) + if returnType != "void": + if returnType == "GLboolean": + print " return static_cast<GLboolean>(reinterpret_cast<int>(ret));" + else: + print " return reinterpret_cast<%s>(ret);" % (returnType) + print "}\n" + + + print "// FIXME: the following functions should be written by hand" + for extern in externs: + print extern + +if __name__ == "__main__": + print """\ +/* + ** 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. + */ + +// auto generated by generate_api_cpp.py + +#include "src/header.h" +#include "src/api.h" + +template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; } +template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; } +""" + lines = open("gl2_api_annotated.in").readlines() + generate_api(lines) + #lines = open("gl2ext_api.in").readlines() + #generate_api(lines) + + diff --git a/opengl/libs/GLES2_dbg/generate_caller_cpp.py b/opengl/libs/GLES2_dbg/generate_caller_cpp.py new file mode 100755 index 0000000..eac2292 --- /dev/null +++ b/opengl/libs/GLES2_dbg/generate_caller_cpp.py @@ -0,0 +1,200 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# +# 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. +# + +import os +import sys + +externs = [] + +def generate_caller(lines): + i = 0 + output = "" + skipFunctions = [] + + for line in lines: + if line.find("API_ENTRY(") >= 0: # a function prototype + returnType = line[0: line.find(" API_ENTRY(")] + functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name + parameterList = line[line.find(")(") + 2: line.find(") {")] + + #if line.find("*") >= 0: + # extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList) + # externs.append(extern) + # continue + + if functionName in skipFunctions: + sys.stderr.write("!\n! skipping function '%s'\n!\n" % functionName) + continue + output += "\ + case glesv2debugger::Message_Function_%s:\n" % functionName + parameters = parameterList.split(',') + paramIndex = 0 + if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer + # add function to list of functions that should be hand written, but generate code anyways + externs.append(functionName) + output += "\ + ret = GenerateCall_%s(dbg, cmd, msg, prevRet);\n\ + break;\n" % (functionName) + continue + elif line.find(":out") >= 0 or line.find(":inout") >= 0: + externs.append(functionName) + output += "\ + ret = GenerateCall_%s(dbg, cmd, msg, prevRet);\n\ + break; // annotated output pointers\n" % (functionName) + continue + + if parameterList == "void": + parameters = [] + arguments = "" + paramNames = [] + inout = "" + getData = "" + + callerMembers = "" + + for parameter in parameters: + const = parameter.find("const") + parameter = parameter.replace("const", "") + parameter = parameter.strip() + paramType = parameter.split(' ')[0] + paramName = parameter.split(' ')[1] + annotation = "" + if parameter.find(":") >= 0: # has annotation + assert inout == "" # only one parameter should be annotated + sys.stderr.write("%s is annotated: %s \n" % (functionName, paramType)) + inout = paramType.split(":")[2] + annotation = paramType.split(":")[1] + paramType = paramType.split(":")[0] + count = 1 + countArg = "" + if annotation.find("*") >= 0: # [1,n] * param + count = int(annotation.split("*")[0]) + countArg = annotation.split("*")[1] + assert countArg in paramNames + elif annotation in paramNames: + count = 1 + countArg = annotation + elif annotation == "GLstring": + annotation = "strlen(%s)" % (paramName) + else: + count = int(annotation) + + paramType += "*" + arguments += "reinterpret_cast<%s>(const_cast<char *>(cmd.data().data()))" % (paramType) + elif paramType == "GLboolean": + arguments += "GLboolean(cmd.arg%d())" % (paramIndex) + else: + arguments += "static_cast<%s>(cmd.arg%d())" % (paramType, paramIndex) + + if paramIndex < len(parameters) - 1: + arguments += ", " + if len(arguments) - arguments.rfind("\n") > 60 : + arguments += "\n\ + " + if const >= 0: + paramType = "const " + paramType + paramNames.append(paramName) + paramIndex += 1 + + if returnType == "void": + output += "\ + dbg->hooks->gl.%s(\n\ + %s);\n\ + break;\n" % (functionName, arguments) + else: + output += "\ + msg.set_ret(static_cast<int>(dbg->hooks->gl.%s(\n\ + %s)));\n\ + if (cmd.has_ret())\n\ + ret = reinterpret_cast<int *>(msg.ret());\n\ + break;\n" % (functionName, arguments) + return output + +if __name__ == "__main__": + + lines = open("gl2_api_annotated.in").readlines() + output = generate_caller(lines) + + out = open("src/caller.cpp", "w") + out.write("""\ +/* + ** 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. + */ + +// auto generated by generate_caller_cpp.py +// implement declarations in caller.h + +#include "header.h" + +namespace android { + +""") + + for extern in externs: + out.write("\ +static const int * GenerateCall_%s(DbgContext * const dbg,\n\ + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);\n" % (extern)) + print("\ +static const int * GenerateCall_%s(DbgContext * const dbg,\n\ + const glesv2debugger::Message & cmd,\n\ + glesv2debugger::Message & msg, const int * const prevRet)\n\ +{ assert(0); return prevRet; }\n" % (extern)) + + out.write( +""" +#include "caller.h" + +const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + LOGD("GenerateCall function=%u", cmd.function()); + const int * ret = prevRet; // only some functions have return value + gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; + nsecs_t c0 = systemTime(timeMode); + switch (cmd.function()) {""") + + out.write(output) + + out.write("""\ + default: + assert(0); + } + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_function(cmd.function()); + msg.set_type(glesv2debugger::Message_Type_AfterCall); + return ret; +} + +}; // name space android { +""") + + diff --git a/opengl/libs/GLES2_dbg/generate_debug_in.py b/opengl/libs/GLES2_dbg/generate_debug_in.py new file mode 100755 index 0000000..1280c6f --- /dev/null +++ b/opengl/libs/GLES2_dbg/generate_debug_in.py @@ -0,0 +1,80 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# +# 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. +# + +import os +import sys + +def append_functions(functions, lines): + i = 0 + for line in lines: + if line.find("API_ENTRY(") >= 0: # a function prototype + returnType = line[0: line.find(" API_ENTRY(")] + functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name + parameterList = line[line.find(")(") + 2: line.find(") {")] + + functions.append(functionName) + #print functionName + continue + + parameters = parameterList.split(',') + paramIndex = 0 + if line.find("*") >= 0: + print "// FIXME: this function has pointers, it should be hand written" + externs.append("%s Tracing_%s(%s);" % (returnType, functionName, parameterList)) + print "%s Tracing_%s(%s)\n{" % (returnType, functionName, parameterList) + + if parameterList == "void": + parameters = [] + + arguments = "" + + for parameter in parameters: + parameter = parameter.replace("const", "") + parameter = parameter.strip() + paramType = parameter.split(' ')[0] + paramName = parameter.split(' ')[1] + + paramIndex += 1 + + return functions + + + +if __name__ == "__main__": + definedFunctions = [] + lines = open("gl2_api_annotated.in").readlines() + definedFunctions = append_functions(definedFunctions, lines) + + output = open("../debug.in", "w") + lines = open("../trace.in").readlines() + output.write("// the following functions are not defined in GLESv2_dbg\n") + for line in lines: + functionName = "" + if line.find("TRACE_GL(") >= 0: # a function prototype + functionName = line.split(',')[1].strip() + elif line.find("TRACE_GL_VOID(") >= 0: # a function prototype + functionName = line[line.find("(") + 1: line.find(",")] #extract GL function name + else: + continue + if functionName in definedFunctions: + #print functionName + continue + else: + output.write(line) + diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py new file mode 100755 index 0000000..466c447 --- /dev/null +++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py @@ -0,0 +1,147 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# +# 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. +# + +import os + +def generate_egl_entries(output, lines, i): + for line in lines: + if line.find("EGL_ENTRY(") >= 0: + line = line.split(",")[1].strip() #extract EGL function name + output.write(" %s = %d;\n" % (line, i)) + i += 1 + return i + + +def generate_gl_entries(output,lines,i): + for line in lines: + if line.find("API_ENTRY(") >= 0: + line = line[line.find("(") + 1: line.find(")")] #extract GL function name + output.write(" %s = %d;\n" % (line, i)) + i += 1 + return i + + +if __name__ == "__main__": + output = open("debugger_message.proto",'w') + output.write("""\ +/* + * 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. + */ + +// do not edit; auto generated by generate_debugger_message_proto.py + +package com.android.glesv2debugger; + +option optimize_for = LITE_RUNTIME; + +message Message +{ + required int32 context_id = 1; // GL context id + enum Function + { +""") + + i = 0; + + lines = open("gl2_api_annotated.in").readlines() + i = generate_gl_entries(output, lines, i) + output.write(" // end of GL functions\n") + + #lines = open("gl2ext_api.in").readlines() + #i = generate_gl_entries(output, lines, i) + #output.write(" // end of GL EXT functions\n") + + lines = open("../EGL/egl_entries.in").readlines() + i = generate_egl_entries(output, lines, i) + output.write(" // end of GL EXT functions\n") + + output.write(" ACK = %d;\n" % (i)) + i += 1 + + output.write(" NEG = %d;\n" % (i)) + i += 1 + + output.write(" CONTINUE = %d;\n" % (i)) + i += 1 + + output.write(" SKIP = %d;\n" % (i)) + i += 1 + + output.write(" SETPROP = %d;\n" % (i)) + i += 1 + + output.write(""" } + required Function function = 2 [default = NEG]; // type/function of message + enum Type + { + BeforeCall = 0; + AfterCall = 1; + Response = 2; // currently used for misc messages + } + required Type type = 3; + required bool expect_response = 4; + optional int32 ret = 5; // return value from previous GL call + optional int32 arg0 = 6; // args to GL call + optional int32 arg1 = 7; + optional int32 arg2 = 8; + optional int32 arg3 = 9; + optional int32 arg4 = 16; + optional int32 arg5 = 17; + optional int32 arg6 = 18; + optional int32 arg7 = 19; + optional int32 arg8 = 20; + + optional bytes data = 10; // variable length data used for GL call + enum DataType + { + ReferencedImage = 0; // for image sourced from ReadPixels + NonreferencedImage = 1; // for image sourced from ReadPixels + }; + optional DataType data_type = 23; // most data types can be inferred from function + optional int32 pixel_format = 24; // used for image data if format and type + optional int32 pixel_type = 25; // cannot be determined from arg + + optional float time = 11; // duration of previous GL call (ms) + enum Prop + { + Capture = 0; // arg0 = true | false + TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h + ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false + }; + optional Prop prop = 21; // used with SETPROP, value in arg0 + optional float clock = 22; // wall clock in seconds +} +""") + + output.close() + + os.system("aprotoc --cpp_out=src --java_out=../../../../../development/tools/glesv2debugger/src debugger_message.proto") + os.system('mv -f "src/debugger_message.pb.cc" "src/debugger_message.pb.cpp"') diff --git a/opengl/libs/GLES2_dbg/gl2_api_annotated.in b/opengl/libs/GLES2_dbg/gl2_api_annotated.in new file mode 100644 index 0000000..227e2eb --- /dev/null +++ b/opengl/libs/GLES2_dbg/gl2_api_annotated.in @@ -0,0 +1,426 @@ +void API_ENTRY(glActiveTexture)(GLenum texture) { + CALL_GL_API(glActiveTexture, texture); +} +void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) { + CALL_GL_API(glAttachShader, program, shader); +} +void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar:GLstring:in name) { + CALL_GL_API(glBindAttribLocation, program, index, name); +} +void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) { + CALL_GL_API(glBindBuffer, target, buffer); +} +void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) { + CALL_GL_API(glBindFramebuffer, target, framebuffer); +} +void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) { + CALL_GL_API(glBindRenderbuffer, target, renderbuffer); +} +void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) { + CALL_GL_API(glBindTexture, target, texture); +} +void API_ENTRY(glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + CALL_GL_API(glBlendColor, red, green, blue, alpha); +} +void API_ENTRY(glBlendEquation)( GLenum mode ) { + CALL_GL_API(glBlendEquation, mode); +} +void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) { + CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha); +} +void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) { + CALL_GL_API(glBlendFunc, sfactor, dfactor); +} +void API_ENTRY(glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { + CALL_GL_API(glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha); +} +void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid:size:in data, GLenum usage) { + CALL_GL_API(glBufferData, target, size, data, usage); +} +void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid:size:in data) { + CALL_GL_API(glBufferSubData, target, offset, size, data); +} +GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) { + CALL_GL_API_RETURN(glCheckFramebufferStatus, target); +} +void API_ENTRY(glClear)(GLbitfield mask) { + CALL_GL_API(glClear, mask); +} +void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + CALL_GL_API(glClearColor, red, green, blue, alpha); +} +void API_ENTRY(glClearDepthf)(GLclampf depth) { + CALL_GL_API(glClearDepthf, depth); +} +void API_ENTRY(glClearStencil)(GLint s) { + CALL_GL_API(glClearStencil, s); +} +void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { + CALL_GL_API(glColorMask, red, green, blue, alpha); +} +void API_ENTRY(glCompileShader)(GLuint shader) { + CALL_GL_API(glCompileShader, shader); +} +void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) { + CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data); +} +void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) { + CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data); +} +void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { + CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border); +} +void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height); +} +GLuint API_ENTRY(glCreateProgram)(void) { + CALL_GL_API_RETURN(glCreateProgram); +} +GLuint API_ENTRY(glCreateShader)(GLenum type) { + CALL_GL_API_RETURN(glCreateShader, type); +} +void API_ENTRY(glCullFace)(GLenum mode) { + CALL_GL_API(glCullFace, mode); +} +void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint:n:in buffers) { + CALL_GL_API(glDeleteBuffers, n, buffers); +} +void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint:n:in framebuffers) { + CALL_GL_API(glDeleteFramebuffers, n, framebuffers); +} +void API_ENTRY(glDeleteProgram)(GLuint program) { + CALL_GL_API(glDeleteProgram, program); +} +void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint:n:in renderbuffers) { + CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers); +} +void API_ENTRY(glDeleteShader)(GLuint shader) { + CALL_GL_API(glDeleteShader, shader); +} +void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint:n:in textures) { + CALL_GL_API(glDeleteTextures, n, textures); +} +void API_ENTRY(glDepthFunc)(GLenum func) { + CALL_GL_API(glDepthFunc, func); +} +void API_ENTRY(glDepthMask)(GLboolean flag) { + CALL_GL_API(glDepthMask, flag); +} +void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) { + CALL_GL_API(glDepthRangef, zNear, zFar); +} +void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) { + CALL_GL_API(glDetachShader, program, shader); +} +void API_ENTRY(glDisable)(GLenum cap) { + CALL_GL_API(glDisable, cap); +} +void API_ENTRY(glDisableVertexAttribArray)(GLuint index) { + CALL_GL_API(glDisableVertexAttribArray, index); +} +void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) { + CALL_GL_API(glDrawArrays, mode, first, count); +} +void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { + CALL_GL_API(glDrawElements, mode, count, type, indices); +} +void API_ENTRY(glEnable)(GLenum cap) { + CALL_GL_API(glEnable, cap); +} +void API_ENTRY(glEnableVertexAttribArray)(GLuint index) { + CALL_GL_API(glEnableVertexAttribArray, index); +} +void API_ENTRY(glFinish)(void) { + CALL_GL_API(glFinish); +} +void API_ENTRY(glFlush)(void) { + CALL_GL_API(glFlush); +} +void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { + CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer); +} +void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { + CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level); +} +void API_ENTRY(glFrontFace)(GLenum mode) { + CALL_GL_API(glFrontFace, mode); +} +void API_ENTRY(glGenBuffers)(GLsizei n, GLuint:n:out buffers) { + CALL_GL_API(glGenBuffers, n, buffers); +} +void API_ENTRY(glGenerateMipmap)(GLenum target) { + CALL_GL_API(glGenerateMipmap, target); +} +void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint:n:out framebuffers) { + CALL_GL_API(glGenFramebuffers, n, framebuffers); +} +void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint:n:out renderbuffers) { + CALL_GL_API(glGenRenderbuffers, n, renderbuffers); +} +void API_ENTRY(glGenTextures)(GLsizei n, GLuint:n:out textures) { + CALL_GL_API(glGenTextures, n, textures); +} +void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar:GLstring:in name) { + CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name); +} +void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar:GLstring:in name) { + CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name); +} +void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) { + CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders); +} +int API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar:GLstring:in name) { + CALL_GL_API_RETURN(glGetAttribLocation, program, name); +} +void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) { + CALL_GL_API(glGetBooleanv, pname, params); +} +void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) { + CALL_GL_API(glGetBufferParameteriv, target, pname, params); +} +GLenum API_ENTRY(glGetError)(void) { + CALL_GL_API_RETURN(glGetError); +} +void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params) { + CALL_GL_API(glGetFloatv, pname, params); +} +void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) { + CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params); +} +void API_ENTRY(glGetIntegerv)(GLenum pname, GLint* params) { + CALL_GL_API(glGetIntegerv, pname, params); +} +void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint:1:out params) { + CALL_GL_API(glGetProgramiv, program, pname, params); +} +void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out infolog) { + CALL_GL_API(glGetProgramInfoLog, program, bufsize, length, infolog); +} +void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) { + CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params); +} +void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint:1:out params) { + CALL_GL_API(glGetShaderiv, shader, pname, params); +} +void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out infolog) { + CALL_GL_API(glGetShaderInfoLog, shader, bufsize, length, infolog); +} +void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { + CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision); +} +void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out source) { + CALL_GL_API(glGetShaderSource, shader, bufsize, length, source); +} +const GLubyte* API_ENTRY(glGetString)(GLenum name) { + CALL_GL_API_RETURN(glGetString, name); +} +void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) { + CALL_GL_API(glGetTexParameterfv, target, pname, params); +} +void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) { + CALL_GL_API(glGetTexParameteriv, target, pname, params); +} +void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params) { + CALL_GL_API(glGetUniformfv, program, location, params); +} +void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) { + CALL_GL_API(glGetUniformiv, program, location, params); +} +int API_ENTRY(glGetUniformLocation)(GLuint program, const GLchar:GLstring:in name) { + CALL_GL_API_RETURN(glGetUniformLocation, program, name); +} +void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) { + CALL_GL_API(glGetVertexAttribfv, index, pname, params); +} +void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) { + CALL_GL_API(glGetVertexAttribiv, index, pname, params); +} +void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer) { + CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer); +} +void API_ENTRY(glHint)(GLenum target, GLenum mode) { + CALL_GL_API(glHint, target, mode); +} +GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { + CALL_GL_API_RETURN(glIsBuffer, buffer); +} +GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { + CALL_GL_API_RETURN(glIsEnabled, cap); +} +GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) { + CALL_GL_API_RETURN(glIsFramebuffer, framebuffer); +} +GLboolean API_ENTRY(glIsProgram)(GLuint program) { + CALL_GL_API_RETURN(glIsProgram, program); +} +GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) { + CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer); +} +GLboolean API_ENTRY(glIsShader)(GLuint shader) { + CALL_GL_API_RETURN(glIsShader, shader); +} +GLboolean API_ENTRY(glIsTexture)(GLuint texture) { + CALL_GL_API_RETURN(glIsTexture, texture); +} +void API_ENTRY(glLineWidth)(GLfloat width) { + CALL_GL_API(glLineWidth, width); +} +void API_ENTRY(glLinkProgram)(GLuint program) { + CALL_GL_API(glLinkProgram, program); +} +void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) { + CALL_GL_API(glPixelStorei, pname, param); +} +void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) { + CALL_GL_API(glPolygonOffset, factor, units); +} +void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) { + CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels); +} +void API_ENTRY(glReleaseShaderCompiler)(void) { + CALL_GL_API(glReleaseShaderCompiler); +} +void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { + CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height); +} +void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) { + CALL_GL_API(glSampleCoverage, value, invert); +} +void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glScissor, x, y, width, height); +} +void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) { + CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length); +} +void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) { + CALL_GL_API(glShaderSource, shader, count, string, length); +} +void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) { + CALL_GL_API(glStencilFunc, func, ref, mask); +} +void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) { + CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask); +} +void API_ENTRY(glStencilMask)(GLuint mask) { + CALL_GL_API(glStencilMask, mask); +} +void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) { + CALL_GL_API(glStencilMaskSeparate, face, mask); +} +void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) { + CALL_GL_API(glStencilOp, fail, zfail, zpass); +} +void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { + CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass); +} +void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { + CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels); +} +void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) { + CALL_GL_API(glTexParameterf, target, pname, param); +} +void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) { + CALL_GL_API(glTexParameterfv, target, pname, params); +} +void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) { + CALL_GL_API(glTexParameteri, target, pname, param); +} +void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) { + CALL_GL_API(glTexParameteriv, target, pname, params); +} +void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) { + CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels); +} +void API_ENTRY(glUniform1f)(GLint location, GLfloat x) { + CALL_GL_API(glUniform1f, location, x); +} +void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat:1*count:in v) { + CALL_GL_API(glUniform1fv, location, count, v); +} +void API_ENTRY(glUniform1i)(GLint location, GLint x) { + CALL_GL_API(glUniform1i, location, x); +} +void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint:1*count:in v) { + CALL_GL_API(glUniform1iv, location, count, v); +} +void API_ENTRY(glUniform2f)(GLint location, GLfloat x, GLfloat y) { + CALL_GL_API(glUniform2f, location, x, y); +} +void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat:2*count:in v) { + CALL_GL_API(glUniform2fv, location, count, v); +} +void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y) { + CALL_GL_API(glUniform2i, location, x, y); +} +void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint:2*count:in v) { + CALL_GL_API(glUniform2iv, location, count, v); +} +void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) { + CALL_GL_API(glUniform3f, location, x, y, z); +} +void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat:3*count:in v) { + CALL_GL_API(glUniform3fv, location, count, v); +} +void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z) { + CALL_GL_API(glUniform3i, location, x, y, z); +} +void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint:3*count:in v) { + CALL_GL_API(glUniform3iv, location, count, v); +} +void API_ENTRY(glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { + CALL_GL_API(glUniform4f, location, x, y, z, w); +} +void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat:4*count:in v) { + CALL_GL_API(glUniform4fv, location, count, v); +} +void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) { + CALL_GL_API(glUniform4i, location, x, y, z, w); +} +void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint:4*count:in v) { + CALL_GL_API(glUniform4iv, location, count, v); +} +void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:4*count:in value) { + CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:9*count:in value) { + CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:16*count:in value) { + CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value); +} +void API_ENTRY(glUseProgram)(GLuint program) { + CALL_GL_API(glUseProgram, program); +} +void API_ENTRY(glValidateProgram)(GLuint program) { + CALL_GL_API(glValidateProgram, program); +} +void API_ENTRY(glVertexAttrib1f)(GLuint indx, GLfloat x) { + CALL_GL_API(glVertexAttrib1f, indx, x); +} +void API_ENTRY(glVertexAttrib1fv)(GLuint indx, const GLfloat:1:in values) { + CALL_GL_API(glVertexAttrib1fv, indx, values); +} +void API_ENTRY(glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) { + CALL_GL_API(glVertexAttrib2f, indx, x, y); +} +void API_ENTRY(glVertexAttrib2fv)(GLuint indx, const GLfloat:2:in values) { + CALL_GL_API(glVertexAttrib2fv, indx, values); +} +void API_ENTRY(glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) { + CALL_GL_API(glVertexAttrib3f, indx, x, y, z); +} +void API_ENTRY(glVertexAttrib3fv)(GLuint indx, const GLfloat:3:in values) { + CALL_GL_API(glVertexAttrib3fv, indx, values); +} +void API_ENTRY(glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { + CALL_GL_API(glVertexAttrib4f, indx, x, y, z, w); +} +void API_ENTRY(glVertexAttrib4fv)(GLuint indx, const GLfloat:4:in values) { + CALL_GL_API(glVertexAttrib4fv, indx, values); +} +void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) { + CALL_GL_API(glVertexAttribPointer, indx, size, type, normalized, stride, ptr); +} +void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glViewport, x, y, width, height); +} diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp new file mode 100644 index 0000000..130ca7e --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/api.cpp @@ -0,0 +1,3467 @@ +/* + ** 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. + */ + +// auto generated by generate_api_cpp.py + +#include "src/header.h" +#include "src/api.h" + +template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; } +template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; } + +void Debug_glActiveTexture(GLenum texture) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum texture; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glActiveTexture(texture); + return 0; + } + } caller; + caller.texture = texture; + + msg.set_arg0(texture); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glActiveTexture); +} + +void Debug_glAttachShader(GLuint program, GLuint shader) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLuint shader; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glAttachShader(program, shader); + return 0; + } + } caller; + caller.program = program; + caller.shader = shader; + + msg.set_arg0(program); + msg.set_arg1(shader); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glAttachShader); +} + +void Debug_glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLuint index; + const GLchar* name; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBindAttribLocation(program, index, name); + return 0; + } + } caller; + caller.program = program; + caller.index = index; + caller.name = name; + + msg.set_arg0(program); + msg.set_arg1(index); + msg.set_arg2(ToInt(name)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindAttribLocation); +} + +void Debug_glBindBuffer(GLenum target, GLuint buffer) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLuint buffer; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBindBuffer(target, buffer); + getDbgContextThreadSpecific()->glBindBuffer(target, buffer); + return 0; + } + } caller; + caller.target = target; + caller.buffer = buffer; + + msg.set_arg0(target); + msg.set_arg1(buffer); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindBuffer); +} + +void Debug_glBindFramebuffer(GLenum target, GLuint framebuffer) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLuint framebuffer; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBindFramebuffer(target, framebuffer); + return 0; + } + } caller; + caller.target = target; + caller.framebuffer = framebuffer; + + msg.set_arg0(target); + msg.set_arg1(framebuffer); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindFramebuffer); +} + +void Debug_glBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLuint renderbuffer; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBindRenderbuffer(target, renderbuffer); + return 0; + } + } caller; + caller.target = target; + caller.renderbuffer = renderbuffer; + + msg.set_arg0(target); + msg.set_arg1(renderbuffer); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindRenderbuffer); +} + +void Debug_glBindTexture(GLenum target, GLuint texture) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLuint texture; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBindTexture(target, texture); + return 0; + } + } caller; + caller.target = target; + caller.texture = texture; + + msg.set_arg0(target); + msg.set_arg1(texture); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindTexture); +} + +void Debug_glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLclampf red; + GLclampf green; + GLclampf blue; + GLclampf alpha; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBlendColor(red, green, blue, alpha); + return 0; + } + } caller; + caller.red = red; + caller.green = green; + caller.blue = blue; + caller.alpha = alpha; + + msg.set_arg0(ToInt(red)); + msg.set_arg1(ToInt(green)); + msg.set_arg2(ToInt(blue)); + msg.set_arg3(ToInt(alpha)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendColor); +} + +void Debug_glBlendEquation( GLenum mode ) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum mode; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBlendEquation(mode); + return 0; + } + } caller; + caller.mode = mode; + + msg.set_arg0(mode); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendEquation); +} + +void Debug_glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum modeRGB; + GLenum modeAlpha; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBlendEquationSeparate(modeRGB, modeAlpha); + return 0; + } + } caller; + caller.modeRGB = modeRGB; + caller.modeAlpha = modeAlpha; + + msg.set_arg0(modeRGB); + msg.set_arg1(modeAlpha); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendEquationSeparate); +} + +void Debug_glBlendFunc(GLenum sfactor, GLenum dfactor) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum sfactor; + GLenum dfactor; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBlendFunc(sfactor, dfactor); + return 0; + } + } caller; + caller.sfactor = sfactor; + caller.dfactor = dfactor; + + msg.set_arg0(sfactor); + msg.set_arg1(dfactor); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendFunc); +} + +void Debug_glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum srcRGB; + GLenum dstRGB; + GLenum srcAlpha; + GLenum dstAlpha; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); + return 0; + } + } caller; + caller.srcRGB = srcRGB; + caller.dstRGB = dstRGB; + caller.srcAlpha = srcAlpha; + caller.dstAlpha = dstAlpha; + + msg.set_arg0(srcRGB); + msg.set_arg1(dstRGB); + msg.set_arg2(srcAlpha); + msg.set_arg3(dstAlpha); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendFuncSeparate); +} + +void Debug_glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLsizeiptr size; + const GLvoid* data; + GLenum usage; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBufferData(target, size, data, usage); + getDbgContextThreadSpecific()->glBufferData(target, size, data, usage); + return 0; + } + } caller; + caller.target = target; + caller.size = size; + caller.data = data; + caller.usage = usage; + + msg.set_arg0(target); + msg.set_arg1(size); + msg.set_arg2(ToInt(data)); + msg.set_arg3(usage); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBufferData); +} + +void Debug_glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLintptr offset; + GLsizeiptr size; + const GLvoid* data; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glBufferSubData(target, offset, size, data); + getDbgContextThreadSpecific()->glBufferSubData(target, offset, size, data); + return 0; + } + } caller; + caller.target = target; + caller.offset = offset; + caller.size = size; + caller.data = data; + + msg.set_arg0(target); + msg.set_arg1(offset); + msg.set_arg2(size); + msg.set_arg3(ToInt(data)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBufferSubData); +} + +GLenum Debug_glCheckFramebufferStatus(GLenum target) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glCheckFramebufferStatus(target)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.target = target; + + msg.set_arg0(target); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCheckFramebufferStatus); + return reinterpret_cast<GLenum>(ret); +} + +void Debug_glClear(GLbitfield mask) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLbitfield mask; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glClear(mask); + return 0; + } + } caller; + caller.mask = mask; + + msg.set_arg0(mask); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClear); +} + +void Debug_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLclampf red; + GLclampf green; + GLclampf blue; + GLclampf alpha; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glClearColor(red, green, blue, alpha); + return 0; + } + } caller; + caller.red = red; + caller.green = green; + caller.blue = blue; + caller.alpha = alpha; + + msg.set_arg0(ToInt(red)); + msg.set_arg1(ToInt(green)); + msg.set_arg2(ToInt(blue)); + msg.set_arg3(ToInt(alpha)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearColor); +} + +void Debug_glClearDepthf(GLclampf depth) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLclampf depth; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glClearDepthf(depth); + return 0; + } + } caller; + caller.depth = depth; + + msg.set_arg0(ToInt(depth)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearDepthf); +} + +void Debug_glClearStencil(GLint s) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint s; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glClearStencil(s); + return 0; + } + } caller; + caller.s = s; + + msg.set_arg0(s); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearStencil); +} + +void Debug_glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLboolean red; + GLboolean green; + GLboolean blue; + GLboolean alpha; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glColorMask(red, green, blue, alpha); + return 0; + } + } caller; + caller.red = red; + caller.green = green; + caller.blue = blue; + caller.alpha = alpha; + + msg.set_arg0(red); + msg.set_arg1(green); + msg.set_arg2(blue); + msg.set_arg3(alpha); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glColorMask); +} + +void Debug_glCompileShader(GLuint shader) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint shader; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glCompileShader(shader); + return 0; + } + } caller; + caller.shader = shader; + + msg.set_arg0(shader); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompileShader); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLint level; + GLenum internalformat; + GLsizei width; + GLsizei height; + GLint border; + GLsizei imageSize; + const GLvoid* data; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); + return 0; + } + } caller; + caller.target = target; + caller.level = level; + caller.internalformat = internalformat; + caller.width = width; + caller.height = height; + caller.border = border; + caller.imageSize = imageSize; + caller.data = data; + + msg.set_arg0(target); + msg.set_arg1(level); + msg.set_arg2(internalformat); + msg.set_arg3(width); + msg.set_arg4(height); + msg.set_arg5(border); + msg.set_arg6(imageSize); + msg.set_arg7(ToInt(data)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompressedTexImage2D); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLint level; + GLint xoffset; + GLint yoffset; + GLsizei width; + GLsizei height; + GLenum format; + GLsizei imageSize; + const GLvoid* data; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); + return 0; + } + } caller; + caller.target = target; + caller.level = level; + caller.xoffset = xoffset; + caller.yoffset = yoffset; + caller.width = width; + caller.height = height; + caller.format = format; + caller.imageSize = imageSize; + caller.data = data; + + msg.set_arg0(target); + msg.set_arg1(level); + msg.set_arg2(xoffset); + msg.set_arg3(yoffset); + msg.set_arg4(width); + msg.set_arg5(height); + msg.set_arg6(format); + msg.set_arg7(imageSize); + msg.set_arg8(ToInt(data)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompressedTexSubImage2D); +} + +void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLint level; + GLenum internalformat; + GLint x; + GLint y; + GLsizei width; + GLsizei height; + GLint border; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); + return 0; + } + } caller; + caller.target = target; + caller.level = level; + caller.internalformat = internalformat; + caller.x = x; + caller.y = y; + caller.width = width; + caller.height = height; + caller.border = border; + + msg.set_arg0(target); + msg.set_arg1(level); + msg.set_arg2(internalformat); + msg.set_arg3(x); + msg.set_arg4(y); + msg.set_arg5(width); + msg.set_arg6(height); + msg.set_arg7(border); + + EXTEND_Debug_glCopyTexImage2D; + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexImage2D); +} + +void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLint level; + GLint xoffset; + GLint yoffset; + GLint x; + GLint y; + GLsizei width; + GLsizei height; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); + return 0; + } + } caller; + caller.target = target; + caller.level = level; + caller.xoffset = xoffset; + caller.yoffset = yoffset; + caller.x = x; + caller.y = y; + caller.width = width; + caller.height = height; + + msg.set_arg0(target); + msg.set_arg1(level); + msg.set_arg2(xoffset); + msg.set_arg3(yoffset); + msg.set_arg4(x); + msg.set_arg5(y); + msg.set_arg6(width); + msg.set_arg7(height); + + EXTEND_Debug_glCopyTexSubImage2D; + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexSubImage2D); +} + +GLuint Debug_glCreateProgram(void) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glCreateProgram()); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCreateProgram); + return reinterpret_cast<GLuint>(ret); +} + +GLuint Debug_glCreateShader(GLenum type) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum type; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glCreateShader(type)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.type = type; + + msg.set_arg0(type); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCreateShader); + return reinterpret_cast<GLuint>(ret); +} + +void Debug_glCullFace(GLenum mode) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum mode; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glCullFace(mode); + return 0; + } + } caller; + caller.mode = mode; + + msg.set_arg0(mode); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCullFace); +} + +void Debug_glDeleteBuffers(GLsizei n, const GLuint* buffers) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + const GLuint* buffers; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDeleteBuffers(n, buffers); + getDbgContextThreadSpecific()->glDeleteBuffers(n, buffers); + return 0; + } + } caller; + caller.n = n; + caller.buffers = buffers; + + msg.set_arg0(n); + msg.set_arg1(ToInt(buffers)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteBuffers); +} + +void Debug_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + const GLuint* framebuffers; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDeleteFramebuffers(n, framebuffers); + return 0; + } + } caller; + caller.n = n; + caller.framebuffers = framebuffers; + + msg.set_arg0(n); + msg.set_arg1(ToInt(framebuffers)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteFramebuffers); +} + +void Debug_glDeleteProgram(GLuint program) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDeleteProgram(program); + return 0; + } + } caller; + caller.program = program; + + msg.set_arg0(program); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteProgram); +} + +void Debug_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + const GLuint* renderbuffers; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDeleteRenderbuffers(n, renderbuffers); + return 0; + } + } caller; + caller.n = n; + caller.renderbuffers = renderbuffers; + + msg.set_arg0(n); + msg.set_arg1(ToInt(renderbuffers)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteRenderbuffers); +} + +void Debug_glDeleteShader(GLuint shader) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint shader; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDeleteShader(shader); + return 0; + } + } caller; + caller.shader = shader; + + msg.set_arg0(shader); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteShader); +} + +void Debug_glDeleteTextures(GLsizei n, const GLuint* textures) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + const GLuint* textures; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDeleteTextures(n, textures); + return 0; + } + } caller; + caller.n = n; + caller.textures = textures; + + msg.set_arg0(n); + msg.set_arg1(ToInt(textures)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteTextures); +} + +void Debug_glDepthFunc(GLenum func) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum func; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDepthFunc(func); + return 0; + } + } caller; + caller.func = func; + + msg.set_arg0(func); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthFunc); +} + +void Debug_glDepthMask(GLboolean flag) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLboolean flag; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDepthMask(flag); + return 0; + } + } caller; + caller.flag = flag; + + msg.set_arg0(flag); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthMask); +} + +void Debug_glDepthRangef(GLclampf zNear, GLclampf zFar) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLclampf zNear; + GLclampf zFar; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDepthRangef(zNear, zFar); + return 0; + } + } caller; + caller.zNear = zNear; + caller.zFar = zFar; + + msg.set_arg0(ToInt(zNear)); + msg.set_arg1(ToInt(zFar)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthRangef); +} + +void Debug_glDetachShader(GLuint program, GLuint shader) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLuint shader; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDetachShader(program, shader); + return 0; + } + } caller; + caller.program = program; + caller.shader = shader; + + msg.set_arg0(program); + msg.set_arg1(shader); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDetachShader); +} + +void Debug_glDisable(GLenum cap) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum cap; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDisable(cap); + return 0; + } + } caller; + caller.cap = cap; + + msg.set_arg0(cap); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDisable); +} + +void Debug_glDisableVertexAttribArray(GLuint index) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint index; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glDisableVertexAttribArray(index); + getDbgContextThreadSpecific()->glDisableVertexAttribArray(index); + return 0; + } + } caller; + caller.index = index; + + msg.set_arg0(index); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDisableVertexAttribArray); +} + +void Debug_glEnable(GLenum cap) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum cap; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glEnable(cap); + return 0; + } + } caller; + caller.cap = cap; + + msg.set_arg0(cap); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glEnable); +} + +void Debug_glEnableVertexAttribArray(GLuint index) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint index; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glEnableVertexAttribArray(index); + getDbgContextThreadSpecific()->glEnableVertexAttribArray(index); + return 0; + } + } caller; + caller.index = index; + + msg.set_arg0(index); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glEnableVertexAttribArray); +} + +void Debug_glFinish(void) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glFinish(); + return 0; + } + } caller; + + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFinish); +} + +void Debug_glFlush(void) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glFlush(); + return 0; + } + } caller; + + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFlush); +} + +void Debug_glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum attachment; + GLenum renderbuffertarget; + GLuint renderbuffer; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); + return 0; + } + } caller; + caller.target = target; + caller.attachment = attachment; + caller.renderbuffertarget = renderbuffertarget; + caller.renderbuffer = renderbuffer; + + msg.set_arg0(target); + msg.set_arg1(attachment); + msg.set_arg2(renderbuffertarget); + msg.set_arg3(renderbuffer); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFramebufferRenderbuffer); +} + +void Debug_glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum attachment; + GLenum textarget; + GLuint texture; + GLint level; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glFramebufferTexture2D(target, attachment, textarget, texture, level); + return 0; + } + } caller; + caller.target = target; + caller.attachment = attachment; + caller.textarget = textarget; + caller.texture = texture; + caller.level = level; + + msg.set_arg0(target); + msg.set_arg1(attachment); + msg.set_arg2(textarget); + msg.set_arg3(texture); + msg.set_arg4(level); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFramebufferTexture2D); +} + +void Debug_glFrontFace(GLenum mode) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum mode; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glFrontFace(mode); + return 0; + } + } caller; + caller.mode = mode; + + msg.set_arg0(mode); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFrontFace); +} + +void Debug_glGenBuffers(GLsizei n, GLuint* buffers) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + GLuint* buffers; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGenBuffers(n, buffers); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint)); + return 0; + } + } caller; + caller.n = n; + caller.buffers = buffers; + + msg.set_arg0(n); + msg.set_arg1(ToInt(buffers)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenBuffers); +} + +void Debug_glGenerateMipmap(GLenum target) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGenerateMipmap(target); + return 0; + } + } caller; + caller.target = target; + + msg.set_arg0(target); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenerateMipmap); +} + +void Debug_glGenFramebuffers(GLsizei n, GLuint* framebuffers) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + GLuint* framebuffers; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGenFramebuffers(n, framebuffers); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint)); + return 0; + } + } caller; + caller.n = n; + caller.framebuffers = framebuffers; + + msg.set_arg0(n); + msg.set_arg1(ToInt(framebuffers)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenFramebuffers); +} + +void Debug_glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + GLuint* renderbuffers; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGenRenderbuffers(n, renderbuffers); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint)); + return 0; + } + } caller; + caller.n = n; + caller.renderbuffers = renderbuffers; + + msg.set_arg0(n); + msg.set_arg1(ToInt(renderbuffers)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenRenderbuffers); +} + +void Debug_glGenTextures(GLsizei n, GLuint* textures) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + GLuint* textures; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGenTextures(n, textures); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint)); + return 0; + } + } caller; + caller.n = n; + caller.textures = textures; + + msg.set_arg0(n); + msg.set_arg1(ToInt(textures)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenTextures); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLuint index; + GLsizei bufsize; + GLsizei* length; + GLint* size; + GLenum* type; + GLchar* name; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetActiveAttrib(program, index, bufsize, length, size, type, name); + return 0; + } + } caller; + caller.program = program; + caller.index = index; + caller.bufsize = bufsize; + caller.length = length; + caller.size = size; + caller.type = type; + caller.name = name; + + msg.set_arg0(program); + msg.set_arg1(index); + msg.set_arg2(bufsize); + msg.set_arg3(ToInt(length)); + msg.set_arg4(ToInt(size)); + msg.set_arg5(ToInt(type)); + msg.set_arg6(ToInt(name)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetActiveAttrib); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLuint index; + GLsizei bufsize; + GLsizei* length; + GLint* size; + GLenum* type; + GLchar* name; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetActiveUniform(program, index, bufsize, length, size, type, name); + return 0; + } + } caller; + caller.program = program; + caller.index = index; + caller.bufsize = bufsize; + caller.length = length; + caller.size = size; + caller.type = type; + caller.name = name; + + msg.set_arg0(program); + msg.set_arg1(index); + msg.set_arg2(bufsize); + msg.set_arg3(ToInt(length)); + msg.set_arg4(ToInt(size)); + msg.set_arg5(ToInt(type)); + msg.set_arg6(ToInt(name)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetActiveUniform); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLsizei maxcount; + GLsizei* count; + GLuint* shaders; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetAttachedShaders(program, maxcount, count, shaders); + return 0; + } + } caller; + caller.program = program; + caller.maxcount = maxcount; + caller.count = count; + caller.shaders = shaders; + + msg.set_arg0(program); + msg.set_arg1(maxcount); + msg.set_arg2(ToInt(count)); + msg.set_arg3(ToInt(shaders)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetAttachedShaders); +} + +int Debug_glGetAttribLocation(GLuint program, const GLchar* name) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + const GLchar* name; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glGetAttribLocation(program, name)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.program = program; + caller.name = name; + + msg.set_arg0(program); + msg.set_arg1(ToInt(name)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetAttribLocation); + return reinterpret_cast<int>(ret); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetBooleanv(GLenum pname, GLboolean* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum pname; + GLboolean* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetBooleanv(pname, params); + return 0; + } + } caller; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(pname); + msg.set_arg1(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetBooleanv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum pname; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetBufferParameteriv(target, pname, params); + return 0; + } + } caller; + caller.target = target; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(target); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetBufferParameteriv); +} + +GLenum Debug_glGetError(void) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glGetError()); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetError); + return reinterpret_cast<GLenum>(ret); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetFloatv(GLenum pname, GLfloat* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum pname; + GLfloat* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetFloatv(pname, params); + return 0; + } + } caller; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(pname); + msg.set_arg1(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetFloatv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum attachment; + GLenum pname; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); + return 0; + } + } caller; + caller.target = target; + caller.attachment = attachment; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(target); + msg.set_arg1(attachment); + msg.set_arg2(pname); + msg.set_arg3(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetIntegerv(GLenum pname, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum pname; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetIntegerv(pname, params); + return 0; + } + } caller; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(pname); + msg.set_arg1(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetIntegerv); +} + +void Debug_glGetProgramiv(GLuint program, GLenum pname, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLenum pname; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGetProgramiv(program, pname, params); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(params), 1 * sizeof(GLint)); + return 0; + } + } caller; + caller.program = program; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(program); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetProgramiv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLsizei bufsize; + GLsizei* length; + GLchar* infolog; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGetProgramInfoLog(program, bufsize, length, infolog); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(infolog), strlen(infolog) * sizeof(GLchar)); + return 0; + } + } caller; + caller.program = program; + caller.bufsize = bufsize; + caller.length = length; + caller.infolog = infolog; + + msg.set_arg0(program); + msg.set_arg1(bufsize); + msg.set_arg2(ToInt(length)); + msg.set_arg3(ToInt(infolog)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetProgramInfoLog); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum pname; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetRenderbufferParameteriv(target, pname, params); + return 0; + } + } caller; + caller.target = target; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(target); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetRenderbufferParameteriv); +} + +void Debug_glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint shader; + GLenum pname; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGetShaderiv(shader, pname, params); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(params), 1 * sizeof(GLint)); + return 0; + } + } caller; + caller.shader = shader; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(shader); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderiv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint shader; + GLsizei bufsize; + GLsizei* length; + GLchar* infolog; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGetShaderInfoLog(shader, bufsize, length, infolog); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(infolog), strlen(infolog) * sizeof(GLchar)); + return 0; + } + } caller; + caller.shader = shader; + caller.bufsize = bufsize; + caller.length = length; + caller.infolog = infolog; + + msg.set_arg0(shader); + msg.set_arg1(bufsize); + msg.set_arg2(ToInt(length)); + msg.set_arg3(ToInt(infolog)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderInfoLog); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum shadertype; + GLenum precisiontype; + GLint* range; + GLint* precision; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); + return 0; + } + } caller; + caller.shadertype = shadertype; + caller.precisiontype = precisiontype; + caller.range = range; + caller.precision = precision; + + msg.set_arg0(shadertype); + msg.set_arg1(precisiontype); + msg.set_arg2(ToInt(range)); + msg.set_arg3(ToInt(precision)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderPrecisionFormat); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint shader; + GLsizei bufsize; + GLsizei* length; + GLchar* source; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + nsecs_t c0 = systemTime(timeMode); + _c->glGetShaderSource(shader, bufsize, length, source); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.mutable_data()->assign(reinterpret_cast<const char *>(source), strlen(source) * sizeof(GLchar)); + return 0; + } + } caller; + caller.shader = shader; + caller.bufsize = bufsize; + caller.length = length; + caller.source = source; + + msg.set_arg0(shader); + msg.set_arg1(bufsize); + msg.set_arg2(ToInt(length)); + msg.set_arg3(ToInt(source)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderSource); +} + +// FIXME: this function has pointers, it should be hand written +const GLubyte* Debug_glGetString(GLenum name) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum name; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glGetString(name)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.name = name; + + msg.set_arg0(name); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetString); + return reinterpret_cast<const GLubyte*>(ret); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum pname; + GLfloat* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetTexParameterfv(target, pname, params); + return 0; + } + } caller; + caller.target = target; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(target); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetTexParameterfv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum pname; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetTexParameteriv(target, pname, params); + return 0; + } + } caller; + caller.target = target; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(target); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetTexParameteriv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLint location; + GLfloat* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetUniformfv(program, location, params); + return 0; + } + } caller; + caller.program = program; + caller.location = location; + caller.params = params; + + msg.set_arg0(program); + msg.set_arg1(location); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformfv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + GLint location; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetUniformiv(program, location, params); + return 0; + } + } caller; + caller.program = program; + caller.location = location; + caller.params = params; + + msg.set_arg0(program); + msg.set_arg1(location); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformiv); +} + +int Debug_glGetUniformLocation(GLuint program, const GLchar* name) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + const GLchar* name; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glGetUniformLocation(program, name)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.program = program; + caller.name = name; + + msg.set_arg0(program); + msg.set_arg1(ToInt(name)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformLocation); + return reinterpret_cast<int>(ret); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint index; + GLenum pname; + GLfloat* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetVertexAttribfv(index, pname, params); + return 0; + } + } caller; + caller.index = index; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(index); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribfv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint index; + GLenum pname; + GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetVertexAttribiv(index, pname, params); + return 0; + } + } caller; + caller.index = index; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(index); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribiv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint index; + GLenum pname; + GLvoid** pointer; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glGetVertexAttribPointerv(index, pname, pointer); + return 0; + } + } caller; + caller.index = index; + caller.pname = pname; + caller.pointer = pointer; + + msg.set_arg0(index); + msg.set_arg1(pname); + msg.set_arg2(ToInt(pointer)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribPointerv); +} + +void Debug_glHint(GLenum target, GLenum mode) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum mode; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glHint(target, mode); + return 0; + } + } caller; + caller.target = target; + caller.mode = mode; + + msg.set_arg0(target); + msg.set_arg1(mode); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glHint); +} + +GLboolean Debug_glIsBuffer(GLuint buffer) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint buffer; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glIsBuffer(buffer)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.buffer = buffer; + + msg.set_arg0(buffer); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsBuffer); + return static_cast<GLboolean>(reinterpret_cast<int>(ret)); +} + +GLboolean Debug_glIsEnabled(GLenum cap) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum cap; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glIsEnabled(cap)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.cap = cap; + + msg.set_arg0(cap); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsEnabled); + return static_cast<GLboolean>(reinterpret_cast<int>(ret)); +} + +GLboolean Debug_glIsFramebuffer(GLuint framebuffer) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint framebuffer; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glIsFramebuffer(framebuffer)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.framebuffer = framebuffer; + + msg.set_arg0(framebuffer); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsFramebuffer); + return static_cast<GLboolean>(reinterpret_cast<int>(ret)); +} + +GLboolean Debug_glIsProgram(GLuint program) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glIsProgram(program)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.program = program; + + msg.set_arg0(program); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsProgram); + return static_cast<GLboolean>(reinterpret_cast<int>(ret)); +} + +GLboolean Debug_glIsRenderbuffer(GLuint renderbuffer) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint renderbuffer; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glIsRenderbuffer(renderbuffer)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.renderbuffer = renderbuffer; + + msg.set_arg0(renderbuffer); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsRenderbuffer); + return static_cast<GLboolean>(reinterpret_cast<int>(ret)); +} + +GLboolean Debug_glIsShader(GLuint shader) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint shader; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glIsShader(shader)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.shader = shader; + + msg.set_arg0(shader); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsShader); + return static_cast<GLboolean>(reinterpret_cast<int>(ret)); +} + +GLboolean Debug_glIsTexture(GLuint texture) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint texture; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + const int * ret = reinterpret_cast<const int *>(_c->glIsTexture(texture)); + msg.set_ret(ToInt(ret)); + return ret; + } + } caller; + caller.texture = texture; + + msg.set_arg0(texture); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsTexture); + return static_cast<GLboolean>(reinterpret_cast<int>(ret)); +} + +void Debug_glLineWidth(GLfloat width) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLfloat width; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glLineWidth(width); + return 0; + } + } caller; + caller.width = width; + + msg.set_arg0(ToInt(width)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glLineWidth); +} + +void Debug_glLinkProgram(GLuint program) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glLinkProgram(program); + return 0; + } + } caller; + caller.program = program; + + msg.set_arg0(program); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glLinkProgram); +} + +void Debug_glPixelStorei(GLenum pname, GLint param) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum pname; + GLint param; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glPixelStorei(pname, param); + return 0; + } + } caller; + caller.pname = pname; + caller.param = param; + + msg.set_arg0(pname); + msg.set_arg1(param); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPixelStorei); +} + +void Debug_glPolygonOffset(GLfloat factor, GLfloat units) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLfloat factor; + GLfloat units; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glPolygonOffset(factor, units); + return 0; + } + } caller; + caller.factor = factor; + caller.units = units; + + msg.set_arg0(ToInt(factor)); + msg.set_arg1(ToInt(units)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPolygonOffset); +} + +void Debug_glReleaseShaderCompiler(void) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glReleaseShaderCompiler(); + return 0; + } + } caller; + + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReleaseShaderCompiler); +} + +void Debug_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum internalformat; + GLsizei width; + GLsizei height; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glRenderbufferStorage(target, internalformat, width, height); + return 0; + } + } caller; + caller.target = target; + caller.internalformat = internalformat; + caller.width = width; + caller.height = height; + + msg.set_arg0(target); + msg.set_arg1(internalformat); + msg.set_arg2(width); + msg.set_arg3(height); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glRenderbufferStorage); +} + +void Debug_glSampleCoverage(GLclampf value, GLboolean invert) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLclampf value; + GLboolean invert; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glSampleCoverage(value, invert); + return 0; + } + } caller; + caller.value = value; + caller.invert = invert; + + msg.set_arg0(ToInt(value)); + msg.set_arg1(invert); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glSampleCoverage); +} + +void Debug_glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint x; + GLint y; + GLsizei width; + GLsizei height; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glScissor(x, y, width, height); + return 0; + } + } caller; + caller.x = x; + caller.y = y; + caller.width = width; + caller.height = height; + + msg.set_arg0(x); + msg.set_arg1(y); + msg.set_arg2(width); + msg.set_arg3(height); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glScissor); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLsizei n; + const GLuint* shaders; + GLenum binaryformat; + const GLvoid* binary; + GLsizei length; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glShaderBinary(n, shaders, binaryformat, binary, length); + return 0; + } + } caller; + caller.n = n; + caller.shaders = shaders; + caller.binaryformat = binaryformat; + caller.binary = binary; + caller.length = length; + + msg.set_arg0(n); + msg.set_arg1(ToInt(shaders)); + msg.set_arg2(binaryformat); + msg.set_arg3(ToInt(binary)); + msg.set_arg4(length); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderBinary); +} + +void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint shader; + GLsizei count; + const GLchar** string; + const GLint* length; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glShaderSource(shader, count, string, length); + return 0; + } + } caller; + caller.shader = shader; + caller.count = count; + caller.string = string; + caller.length = length; + + msg.set_arg0(shader); + msg.set_arg1(count); + msg.set_arg2(ToInt(string)); + msg.set_arg3(ToInt(length)); + + // FIXME: check for pointer usage + EXTEND_Debug_glShaderSource; + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderSource); +} + +void Debug_glStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum func; + GLint ref; + GLuint mask; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glStencilFunc(func, ref, mask); + return 0; + } + } caller; + caller.func = func; + caller.ref = ref; + caller.mask = mask; + + msg.set_arg0(func); + msg.set_arg1(ref); + msg.set_arg2(mask); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilFunc); +} + +void Debug_glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum face; + GLenum func; + GLint ref; + GLuint mask; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glStencilFuncSeparate(face, func, ref, mask); + return 0; + } + } caller; + caller.face = face; + caller.func = func; + caller.ref = ref; + caller.mask = mask; + + msg.set_arg0(face); + msg.set_arg1(func); + msg.set_arg2(ref); + msg.set_arg3(mask); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilFuncSeparate); +} + +void Debug_glStencilMask(GLuint mask) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint mask; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glStencilMask(mask); + return 0; + } + } caller; + caller.mask = mask; + + msg.set_arg0(mask); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilMask); +} + +void Debug_glStencilMaskSeparate(GLenum face, GLuint mask) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum face; + GLuint mask; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glStencilMaskSeparate(face, mask); + return 0; + } + } caller; + caller.face = face; + caller.mask = mask; + + msg.set_arg0(face); + msg.set_arg1(mask); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilMaskSeparate); +} + +void Debug_glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum fail; + GLenum zfail; + GLenum zpass; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glStencilOp(fail, zfail, zpass); + return 0; + } + } caller; + caller.fail = fail; + caller.zfail = zfail; + caller.zpass = zpass; + + msg.set_arg0(fail); + msg.set_arg1(zfail); + msg.set_arg2(zpass); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilOp); +} + +void Debug_glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum face; + GLenum fail; + GLenum zfail; + GLenum zpass; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glStencilOpSeparate(face, fail, zfail, zpass); + return 0; + } + } caller; + caller.face = face; + caller.fail = fail; + caller.zfail = zfail; + caller.zpass = zpass; + + msg.set_arg0(face); + msg.set_arg1(fail); + msg.set_arg2(zfail); + msg.set_arg3(zpass); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilOpSeparate); +} + +void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLint level; + GLint internalformat; + GLsizei width; + GLsizei height; + GLint border; + GLenum format; + GLenum type; + const GLvoid* pixels; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + return 0; + } + } caller; + caller.target = target; + caller.level = level; + caller.internalformat = internalformat; + caller.width = width; + caller.height = height; + caller.border = border; + caller.format = format; + caller.type = type; + caller.pixels = pixels; + + msg.set_arg0(target); + msg.set_arg1(level); + msg.set_arg2(internalformat); + msg.set_arg3(width); + msg.set_arg4(height); + msg.set_arg5(border); + msg.set_arg6(format); + msg.set_arg7(type); + msg.set_arg8(ToInt(pixels)); + + // FIXME: check for pointer usage + EXTEND_Debug_glTexImage2D; + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexImage2D); +} + +void Debug_glTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum pname; + GLfloat param; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glTexParameterf(target, pname, param); + return 0; + } + } caller; + caller.target = target; + caller.pname = pname; + caller.param = param; + + msg.set_arg0(target); + msg.set_arg1(pname); + msg.set_arg2(ToInt(param)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameterf); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum pname; + const GLfloat* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glTexParameterfv(target, pname, params); + return 0; + } + } caller; + caller.target = target; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(target); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameterfv); +} + +void Debug_glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum pname; + GLint param; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glTexParameteri(target, pname, param); + return 0; + } + } caller; + caller.target = target; + caller.pname = pname; + caller.param = param; + + msg.set_arg0(target); + msg.set_arg1(pname); + msg.set_arg2(param); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameteri); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLenum pname; + const GLint* params; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glTexParameteriv(target, pname, params); + return 0; + } + } caller; + caller.target = target; + caller.pname = pname; + caller.params = params; + + msg.set_arg0(target); + msg.set_arg1(pname); + msg.set_arg2(ToInt(params)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameteriv); +} + +void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLenum target; + GLint level; + GLint xoffset; + GLint yoffset; + GLsizei width; + GLsizei height; + GLenum format; + GLenum type; + const GLvoid* pixels; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); + return 0; + } + } caller; + caller.target = target; + caller.level = level; + caller.xoffset = xoffset; + caller.yoffset = yoffset; + caller.width = width; + caller.height = height; + caller.format = format; + caller.type = type; + caller.pixels = pixels; + + msg.set_arg0(target); + msg.set_arg1(level); + msg.set_arg2(xoffset); + msg.set_arg3(yoffset); + msg.set_arg4(width); + msg.set_arg5(height); + msg.set_arg6(format); + msg.set_arg7(type); + msg.set_arg8(ToInt(pixels)); + + // FIXME: check for pointer usage + EXTEND_Debug_glTexSubImage2D; + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexSubImage2D); +} + +void Debug_glUniform1f(GLint location, GLfloat x) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLfloat x; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform1f(location, x); + return 0; + } + } caller; + caller.location = location; + caller.x = x; + + msg.set_arg0(location); + msg.set_arg1(ToInt(x)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1f); +} + +void Debug_glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + const GLfloat* v; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform1fv(location, count, v); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.v = v; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(ToInt(v)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1fv); +} + +void Debug_glUniform1i(GLint location, GLint x) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLint x; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform1i(location, x); + return 0; + } + } caller; + caller.location = location; + caller.x = x; + + msg.set_arg0(location); + msg.set_arg1(x); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1i); +} + +void Debug_glUniform1iv(GLint location, GLsizei count, const GLint* v) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + const GLint* v; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform1iv(location, count, v); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.v = v; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(ToInt(v)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLint)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1iv); +} + +void Debug_glUniform2f(GLint location, GLfloat x, GLfloat y) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLfloat x; + GLfloat y; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform2f(location, x, y); + return 0; + } + } caller; + caller.location = location; + caller.x = x; + caller.y = y; + + msg.set_arg0(location); + msg.set_arg1(ToInt(x)); + msg.set_arg2(ToInt(y)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2f); +} + +void Debug_glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + const GLfloat* v; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform2fv(location, count, v); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.v = v; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(ToInt(v)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2fv); +} + +void Debug_glUniform2i(GLint location, GLint x, GLint y) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLint x; + GLint y; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform2i(location, x, y); + return 0; + } + } caller; + caller.location = location; + caller.x = x; + caller.y = y; + + msg.set_arg0(location); + msg.set_arg1(x); + msg.set_arg2(y); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2i); +} + +void Debug_glUniform2iv(GLint location, GLsizei count, const GLint* v) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + const GLint* v; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform2iv(location, count, v); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.v = v; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(ToInt(v)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLint)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2iv); +} + +void Debug_glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLfloat x; + GLfloat y; + GLfloat z; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform3f(location, x, y, z); + return 0; + } + } caller; + caller.location = location; + caller.x = x; + caller.y = y; + caller.z = z; + + msg.set_arg0(location); + msg.set_arg1(ToInt(x)); + msg.set_arg2(ToInt(y)); + msg.set_arg3(ToInt(z)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3f); +} + +void Debug_glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + const GLfloat* v; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform3fv(location, count, v); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.v = v; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(ToInt(v)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3fv); +} + +void Debug_glUniform3i(GLint location, GLint x, GLint y, GLint z) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLint x; + GLint y; + GLint z; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform3i(location, x, y, z); + return 0; + } + } caller; + caller.location = location; + caller.x = x; + caller.y = y; + caller.z = z; + + msg.set_arg0(location); + msg.set_arg1(x); + msg.set_arg2(y); + msg.set_arg3(z); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3i); +} + +void Debug_glUniform3iv(GLint location, GLsizei count, const GLint* v) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + const GLint* v; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform3iv(location, count, v); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.v = v; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(ToInt(v)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLint)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3iv); +} + +void Debug_glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLfloat x; + GLfloat y; + GLfloat z; + GLfloat w; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform4f(location, x, y, z, w); + return 0; + } + } caller; + caller.location = location; + caller.x = x; + caller.y = y; + caller.z = z; + caller.w = w; + + msg.set_arg0(location); + msg.set_arg1(ToInt(x)); + msg.set_arg2(ToInt(y)); + msg.set_arg3(ToInt(z)); + msg.set_arg4(ToInt(w)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4f); +} + +void Debug_glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + const GLfloat* v; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform4fv(location, count, v); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.v = v; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(ToInt(v)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4fv); +} + +void Debug_glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLint x; + GLint y; + GLint z; + GLint w; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform4i(location, x, y, z, w); + return 0; + } + } caller; + caller.location = location; + caller.x = x; + caller.y = y; + caller.z = z; + caller.w = w; + + msg.set_arg0(location); + msg.set_arg1(x); + msg.set_arg2(y); + msg.set_arg3(z); + msg.set_arg4(w); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4i); +} + +void Debug_glUniform4iv(GLint location, GLsizei count, const GLint* v) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + const GLint* v; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniform4iv(location, count, v); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.v = v; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(ToInt(v)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLint)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4iv); +} + +void Debug_glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + GLboolean transpose; + const GLfloat* value; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniformMatrix2fv(location, count, transpose, value); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.transpose = transpose; + caller.value = value; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(transpose); + msg.set_arg3(ToInt(value)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 4*count * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix2fv); +} + +void Debug_glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + GLboolean transpose; + const GLfloat* value; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniformMatrix3fv(location, count, transpose, value); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.transpose = transpose; + caller.value = value; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(transpose); + msg.set_arg3(ToInt(value)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 9*count * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix3fv); +} + +void Debug_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint location; + GLsizei count; + GLboolean transpose; + const GLfloat* value; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUniformMatrix4fv(location, count, transpose, value); + return 0; + } + } caller; + caller.location = location; + caller.count = count; + caller.transpose = transpose; + caller.value = value; + + msg.set_arg0(location); + msg.set_arg1(count); + msg.set_arg2(transpose); + msg.set_arg3(ToInt(value)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 16*count * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix4fv); +} + +void Debug_glUseProgram(GLuint program) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glUseProgram(program); + getDbgContextThreadSpecific()->glUseProgram(program); + return 0; + } + } caller; + caller.program = program; + + msg.set_arg0(program); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUseProgram); +} + +void Debug_glValidateProgram(GLuint program) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint program; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glValidateProgram(program); + return 0; + } + } caller; + caller.program = program; + + msg.set_arg0(program); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glValidateProgram); +} + +void Debug_glVertexAttrib1f(GLuint indx, GLfloat x) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + GLfloat x; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttrib1f(indx, x); + return 0; + } + } caller; + caller.indx = indx; + caller.x = x; + + msg.set_arg0(indx); + msg.set_arg1(ToInt(x)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib1f); +} + +void Debug_glVertexAttrib1fv(GLuint indx, const GLfloat* values) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + const GLfloat* values; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttrib1fv(indx, values); + return 0; + } + } caller; + caller.indx = indx; + caller.values = values; + + msg.set_arg0(indx); + msg.set_arg1(ToInt(values)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 1 * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib1fv); +} + +void Debug_glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + GLfloat x; + GLfloat y; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttrib2f(indx, x, y); + return 0; + } + } caller; + caller.indx = indx; + caller.x = x; + caller.y = y; + + msg.set_arg0(indx); + msg.set_arg1(ToInt(x)); + msg.set_arg2(ToInt(y)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib2f); +} + +void Debug_glVertexAttrib2fv(GLuint indx, const GLfloat* values) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + const GLfloat* values; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttrib2fv(indx, values); + return 0; + } + } caller; + caller.indx = indx; + caller.values = values; + + msg.set_arg0(indx); + msg.set_arg1(ToInt(values)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 2 * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib2fv); +} + +void Debug_glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + GLfloat x; + GLfloat y; + GLfloat z; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttrib3f(indx, x, y, z); + return 0; + } + } caller; + caller.indx = indx; + caller.x = x; + caller.y = y; + caller.z = z; + + msg.set_arg0(indx); + msg.set_arg1(ToInt(x)); + msg.set_arg2(ToInt(y)); + msg.set_arg3(ToInt(z)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib3f); +} + +void Debug_glVertexAttrib3fv(GLuint indx, const GLfloat* values) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + const GLfloat* values; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttrib3fv(indx, values); + return 0; + } + } caller; + caller.indx = indx; + caller.values = values; + + msg.set_arg0(indx); + msg.set_arg1(ToInt(values)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 3 * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib3fv); +} + +void Debug_glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + GLfloat x; + GLfloat y; + GLfloat z; + GLfloat w; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttrib4f(indx, x, y, z, w); + return 0; + } + } caller; + caller.indx = indx; + caller.x = x; + caller.y = y; + caller.z = z; + caller.w = w; + + msg.set_arg0(indx); + msg.set_arg1(ToInt(x)); + msg.set_arg2(ToInt(y)); + msg.set_arg3(ToInt(z)); + msg.set_arg4(ToInt(w)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib4f); +} + +void Debug_glVertexAttrib4fv(GLuint indx, const GLfloat* values) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + const GLfloat* values; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttrib4fv(indx, values); + return 0; + } + } caller; + caller.indx = indx; + caller.values = values; + + msg.set_arg0(indx); + msg.set_arg1(ToInt(values)); + + // FIXME: check for pointer usage + msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 4 * sizeof(GLfloat)); + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib4fv); +} + +// FIXME: this function has pointers, it should be hand written +void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLuint indx; + GLint size; + GLenum type; + GLboolean normalized; + GLsizei stride; + const GLvoid* ptr; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glVertexAttribPointer(indx, size, type, normalized, stride, ptr); + getDbgContextThreadSpecific()->glVertexAttribPointer(indx, size, type, normalized, stride, ptr); + return 0; + } + } caller; + caller.indx = indx; + caller.size = size; + caller.type = type; + caller.normalized = normalized; + caller.stride = stride; + caller.ptr = ptr; + + msg.set_arg0(indx); + msg.set_arg1(size); + msg.set_arg2(type); + msg.set_arg3(normalized); + msg.set_arg4(stride); + msg.set_arg5(ToInt(ptr)); + + // FIXME: check for pointer usage + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttribPointer); +} + +void Debug_glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + GLint x; + GLint y; + GLsizei width; + GLsizei height; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + _c->glViewport(x, y, width, height); + return 0; + } + } caller; + caller.x = x; + caller.y = y; + caller.width = width; + caller.height = height; + + msg.set_arg0(x); + msg.set_arg1(y); + msg.set_arg2(width); + msg.set_arg3(height); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glViewport); +} + +// FIXME: the following functions should be written by hand +void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data); +void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data); +void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); +void Debug_glGetBooleanv(GLenum pname, GLboolean* params); +void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params); +void Debug_glGetFloatv(GLenum pname, GLfloat* params); +void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params); +void Debug_glGetIntegerv(GLenum pname, GLint* params); +void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog); +void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params); +void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog); +void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); +void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); +const GLubyte* Debug_glGetString(GLenum name); +void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params); +void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params); +void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params); +void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params); +void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params); +void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params); +void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer); +void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length); +void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params); +void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params); +void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr); diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h new file mode 100644 index 0000000..93aef62 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/api.h @@ -0,0 +1,50 @@ +/* + ** 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. + */ + +#define EXTEND_Debug_glCopyTexImage2D \ + DbgContext * const dbg = getDbgContextThreadSpecific(); \ + GLint readFormat, readType; \ + dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); \ + dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); \ + unsigned readSize = GetBytesPerPixel(readFormat, readType) * width * height; \ + void * readData = dbg->GetReadPixelsBuffer(readSize); \ + dbg->hooks->gl.glReadPixels(x, y, width, height, readFormat, readType, readData); \ + const unsigned compressedSize = dbg->CompressReadPixelBuffer(); \ + msg.set_data(dbg->lzf_buf, compressedSize); \ + msg.set_data_type(msg.ReferencedImage); \ + msg.set_pixel_format(readFormat); \ + msg.set_pixel_type(readType); + +#define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D + +#define EXTEND_Debug_glShaderSource \ + std::string * const data = msg.mutable_data(); \ + for (unsigned i = 0; i < count; i++) \ + if (!length || length[i] < 0) \ + data->append(string[i]); \ + else \ + data->append(string[i], length[i]); + +#define EXTEND_Debug_glTexImage2D \ + if (pixels) { \ + DbgContext * const dbg = getDbgContextThreadSpecific(); \ + const unsigned size = GetBytesPerPixel(format, type) * width * height; \ + assert(0 < size); \ + unsigned compressedSize = dbg->Compress(pixels, size); \ + msg.set_data(dbg->lzf_buf, compressedSize); \ + } + +#define EXTEND_Debug_glTexSubImage2D EXTEND_Debug_glTexImage2D diff --git a/opengl/libs/GLES2_dbg/src/caller.cpp b/opengl/libs/GLES2_dbg/src/caller.cpp new file mode 100644 index 0000000..9992f05 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/caller.cpp @@ -0,0 +1,779 @@ +/* + ** 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. + */ + +// auto generated by generate_caller_cpp.py +// implement declarations in caller.h + +#include "header.h" + +namespace android { + +static const int * GenerateCall_glCompressedTexImage2D(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glCompressedTexSubImage2D(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glDrawElements(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGenBuffers(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGenFramebuffers(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGenRenderbuffers(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGenTextures(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetActiveAttrib(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetActiveUniform(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetAttachedShaders(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetBooleanv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetBufferParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetFloatv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetFramebufferAttachmentParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetIntegerv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetRenderbufferParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetShaderPrecisionFormat(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetShaderSource(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetString(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetTexParameterfv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetTexParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetUniformfv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetUniformiv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetVertexAttribfv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetVertexAttribiv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glGetVertexAttribPointerv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glReadPixels(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glShaderBinary(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glShaderSource(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glTexImage2D(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glTexParameterfv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glTexParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glTexSubImage2D(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); +static const int * GenerateCall_glVertexAttribPointer(DbgContext * const dbg, + const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet); + +#include "caller.h" + +const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + LOGD("GenerateCall function=%u", cmd.function()); + const int * ret = prevRet; // only some functions have return value + gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; + nsecs_t c0 = systemTime(timeMode); + switch (cmd.function()) { case glesv2debugger::Message_Function_glActiveTexture: + dbg->hooks->gl.glActiveTexture( + static_cast<GLenum>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glAttachShader: + dbg->hooks->gl.glAttachShader( + static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glBindAttribLocation: + dbg->hooks->gl.glBindAttribLocation( + static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()), + reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glBindBuffer: + dbg->hooks->gl.glBindBuffer( + static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glBindFramebuffer: + dbg->hooks->gl.glBindFramebuffer( + static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glBindRenderbuffer: + dbg->hooks->gl.glBindRenderbuffer( + static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glBindTexture: + dbg->hooks->gl.glBindTexture( + static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glBlendColor: + dbg->hooks->gl.glBlendColor( + static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()), + static_cast<GLclampf>(cmd.arg2()), static_cast<GLclampf>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glBlendEquation: + dbg->hooks->gl.glBlendEquation( + static_cast<GLenum>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glBlendEquationSeparate: + dbg->hooks->gl.glBlendEquationSeparate( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glBlendFunc: + dbg->hooks->gl.glBlendFunc( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glBlendFuncSeparate: + dbg->hooks->gl.glBlendFuncSeparate( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLenum>(cmd.arg2()), static_cast<GLenum>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glBufferData: + dbg->hooks->gl.glBufferData( + static_cast<GLenum>(cmd.arg0()), static_cast<GLsizeiptr>(cmd.arg1()), + reinterpret_cast<GLvoid*>(const_cast<char *>(cmd.data().data())), + static_cast<GLenum>(cmd.arg3())); + break; + case glesv2debugger::Message_Function_glBufferSubData: + dbg->hooks->gl.glBufferSubData( + static_cast<GLenum>(cmd.arg0()), static_cast<GLintptr>(cmd.arg1()), + static_cast<GLsizeiptr>(cmd.arg2()), reinterpret_cast<GLvoid*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glCheckFramebufferStatus: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glCheckFramebufferStatus( + static_cast<GLenum>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glClear: + dbg->hooks->gl.glClear( + static_cast<GLbitfield>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glClearColor: + dbg->hooks->gl.glClearColor( + static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()), + static_cast<GLclampf>(cmd.arg2()), static_cast<GLclampf>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glClearDepthf: + dbg->hooks->gl.glClearDepthf( + static_cast<GLclampf>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glClearStencil: + dbg->hooks->gl.glClearStencil( + static_cast<GLint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glColorMask: + dbg->hooks->gl.glColorMask( + GLboolean(cmd.arg0()), GLboolean(cmd.arg1()), GLboolean(cmd.arg2()), + GLboolean(cmd.arg3())); + break; + case glesv2debugger::Message_Function_glCompileShader: + dbg->hooks->gl.glCompileShader( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glCompressedTexImage2D: + ret = GenerateCall_glCompressedTexImage2D(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glCompressedTexSubImage2D: + ret = GenerateCall_glCompressedTexSubImage2D(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glCopyTexImage2D: + dbg->hooks->gl.glCopyTexImage2D( + static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLenum>(cmd.arg2()), static_cast<GLint>(cmd.arg3()), + static_cast<GLint>(cmd.arg4()), static_cast<GLsizei>(cmd.arg5()), + static_cast<GLsizei>(cmd.arg6()), static_cast<GLint>(cmd.arg7()) + ); + break; + case glesv2debugger::Message_Function_glCopyTexSubImage2D: + dbg->hooks->gl.glCopyTexSubImage2D( + static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()), + static_cast<GLint>(cmd.arg4()), static_cast<GLint>(cmd.arg5()), + static_cast<GLsizei>(cmd.arg6()), static_cast<GLsizei>(cmd.arg7()) + ); + break; + case glesv2debugger::Message_Function_glCreateProgram: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glCreateProgram( + ))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glCreateShader: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glCreateShader( + static_cast<GLenum>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glCullFace: + dbg->hooks->gl.glCullFace( + static_cast<GLenum>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glDeleteBuffers: + dbg->hooks->gl.glDeleteBuffers( + static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glDeleteFramebuffers: + dbg->hooks->gl.glDeleteFramebuffers( + static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glDeleteProgram: + dbg->hooks->gl.glDeleteProgram( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glDeleteRenderbuffers: + dbg->hooks->gl.glDeleteRenderbuffers( + static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glDeleteShader: + dbg->hooks->gl.glDeleteShader( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glDeleteTextures: + dbg->hooks->gl.glDeleteTextures( + static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glDepthFunc: + dbg->hooks->gl.glDepthFunc( + static_cast<GLenum>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glDepthMask: + dbg->hooks->gl.glDepthMask( + GLboolean(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glDepthRangef: + dbg->hooks->gl.glDepthRangef( + static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glDetachShader: + dbg->hooks->gl.glDetachShader( + static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glDisable: + dbg->hooks->gl.glDisable( + static_cast<GLenum>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glDisableVertexAttribArray: + dbg->hooks->gl.glDisableVertexAttribArray( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glDrawArrays: + dbg->hooks->gl.glDrawArrays( + static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLsizei>(cmd.arg2())); + break; + case glesv2debugger::Message_Function_glDrawElements: + ret = GenerateCall_glDrawElements(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glEnable: + dbg->hooks->gl.glEnable( + static_cast<GLenum>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glEnableVertexAttribArray: + dbg->hooks->gl.glEnableVertexAttribArray( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glFinish: + dbg->hooks->gl.glFinish( + ); + break; + case glesv2debugger::Message_Function_glFlush: + dbg->hooks->gl.glFlush( + ); + break; + case glesv2debugger::Message_Function_glFramebufferRenderbuffer: + dbg->hooks->gl.glFramebufferRenderbuffer( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLenum>(cmd.arg2()), static_cast<GLuint>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glFramebufferTexture2D: + dbg->hooks->gl.glFramebufferTexture2D( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLenum>(cmd.arg2()), static_cast<GLuint>(cmd.arg3()), + static_cast<GLint>(cmd.arg4())); + break; + case glesv2debugger::Message_Function_glFrontFace: + dbg->hooks->gl.glFrontFace( + static_cast<GLenum>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glGenBuffers: + ret = GenerateCall_glGenBuffers(dbg, cmd, msg, prevRet); + break; // annotated output pointers + case glesv2debugger::Message_Function_glGenerateMipmap: + dbg->hooks->gl.glGenerateMipmap( + static_cast<GLenum>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glGenFramebuffers: + ret = GenerateCall_glGenFramebuffers(dbg, cmd, msg, prevRet); + break; // annotated output pointers + case glesv2debugger::Message_Function_glGenRenderbuffers: + ret = GenerateCall_glGenRenderbuffers(dbg, cmd, msg, prevRet); + break; // annotated output pointers + case glesv2debugger::Message_Function_glGenTextures: + ret = GenerateCall_glGenTextures(dbg, cmd, msg, prevRet); + break; // annotated output pointers + case glesv2debugger::Message_Function_glGetActiveAttrib: + ret = GenerateCall_glGetActiveAttrib(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetActiveUniform: + ret = GenerateCall_glGetActiveUniform(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetAttachedShaders: + ret = GenerateCall_glGetAttachedShaders(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetAttribLocation: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetAttribLocation( + static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data())) + ))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glGetBooleanv: + ret = GenerateCall_glGetBooleanv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetBufferParameteriv: + ret = GenerateCall_glGetBufferParameteriv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetError: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetError( + ))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glGetFloatv: + ret = GenerateCall_glGetFloatv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv: + ret = GenerateCall_glGetFramebufferAttachmentParameteriv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetIntegerv: + ret = GenerateCall_glGetIntegerv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetProgramiv: + ret = GenerateCall_glGetProgramiv(dbg, cmd, msg, prevRet); + break; // annotated output pointers + case glesv2debugger::Message_Function_glGetProgramInfoLog: + ret = GenerateCall_glGetProgramInfoLog(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetRenderbufferParameteriv: + ret = GenerateCall_glGetRenderbufferParameteriv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetShaderiv: + ret = GenerateCall_glGetShaderiv(dbg, cmd, msg, prevRet); + break; // annotated output pointers + case glesv2debugger::Message_Function_glGetShaderInfoLog: + ret = GenerateCall_glGetShaderInfoLog(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetShaderPrecisionFormat: + ret = GenerateCall_glGetShaderPrecisionFormat(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetShaderSource: + ret = GenerateCall_glGetShaderSource(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetString: + ret = GenerateCall_glGetString(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetTexParameterfv: + ret = GenerateCall_glGetTexParameterfv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetTexParameteriv: + ret = GenerateCall_glGetTexParameteriv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetUniformfv: + ret = GenerateCall_glGetUniformfv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetUniformiv: + ret = GenerateCall_glGetUniformiv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetUniformLocation: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetUniformLocation( + static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data())) + ))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glGetVertexAttribfv: + ret = GenerateCall_glGetVertexAttribfv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetVertexAttribiv: + ret = GenerateCall_glGetVertexAttribiv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glGetVertexAttribPointerv: + ret = GenerateCall_glGetVertexAttribPointerv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glHint: + dbg->hooks->gl.glHint( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glIsBuffer: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsBuffer( + static_cast<GLuint>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glIsEnabled: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsEnabled( + static_cast<GLenum>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glIsFramebuffer: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsFramebuffer( + static_cast<GLuint>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glIsProgram: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsProgram( + static_cast<GLuint>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glIsRenderbuffer: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsRenderbuffer( + static_cast<GLuint>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glIsShader: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsShader( + static_cast<GLuint>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glIsTexture: + msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsTexture( + static_cast<GLuint>(cmd.arg0())))); + if (cmd.has_ret()) + ret = reinterpret_cast<int *>(msg.ret()); + break; + case glesv2debugger::Message_Function_glLineWidth: + dbg->hooks->gl.glLineWidth( + static_cast<GLfloat>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glLinkProgram: + dbg->hooks->gl.glLinkProgram( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glPixelStorei: + dbg->hooks->gl.glPixelStorei( + static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glPolygonOffset: + dbg->hooks->gl.glPolygonOffset( + static_cast<GLfloat>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glReadPixels: + ret = GenerateCall_glReadPixels(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glReleaseShaderCompiler: + dbg->hooks->gl.glReleaseShaderCompiler( + ); + break; + case glesv2debugger::Message_Function_glRenderbufferStorage: + dbg->hooks->gl.glRenderbufferStorage( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glSampleCoverage: + dbg->hooks->gl.glSampleCoverage( + static_cast<GLclampf>(cmd.arg0()), GLboolean(cmd.arg1())); + break; + case glesv2debugger::Message_Function_glScissor: + dbg->hooks->gl.glScissor( + static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glShaderBinary: + ret = GenerateCall_glShaderBinary(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glShaderSource: + ret = GenerateCall_glShaderSource(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glStencilFunc: + dbg->hooks->gl.glStencilFunc( + static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLuint>(cmd.arg2())); + break; + case glesv2debugger::Message_Function_glStencilFuncSeparate: + dbg->hooks->gl.glStencilFuncSeparate( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLint>(cmd.arg2()), static_cast<GLuint>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glStencilMask: + dbg->hooks->gl.glStencilMask( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glStencilMaskSeparate: + dbg->hooks->gl.glStencilMaskSeparate( + static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glStencilOp: + dbg->hooks->gl.glStencilOp( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLenum>(cmd.arg2())); + break; + case glesv2debugger::Message_Function_glStencilOpSeparate: + dbg->hooks->gl.glStencilOpSeparate( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLenum>(cmd.arg2()), static_cast<GLenum>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glTexImage2D: + ret = GenerateCall_glTexImage2D(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glTexParameterf: + dbg->hooks->gl.glTexParameterf( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLfloat>(cmd.arg2())); + break; + case glesv2debugger::Message_Function_glTexParameterfv: + ret = GenerateCall_glTexParameterfv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glTexParameteri: + dbg->hooks->gl.glTexParameteri( + static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), + static_cast<GLint>(cmd.arg2())); + break; + case glesv2debugger::Message_Function_glTexParameteriv: + ret = GenerateCall_glTexParameteriv(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glTexSubImage2D: + ret = GenerateCall_glTexSubImage2D(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glUniform1f: + dbg->hooks->gl.glUniform1f( + static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glUniform1fv: + dbg->hooks->gl.glUniform1fv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniform1i: + dbg->hooks->gl.glUniform1i( + static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glUniform1iv: + dbg->hooks->gl.glUniform1iv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniform2f: + dbg->hooks->gl.glUniform2f( + static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), + static_cast<GLfloat>(cmd.arg2())); + break; + case glesv2debugger::Message_Function_glUniform2fv: + dbg->hooks->gl.glUniform2fv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniform2i: + dbg->hooks->gl.glUniform2i( + static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLint>(cmd.arg2())); + break; + case glesv2debugger::Message_Function_glUniform2iv: + dbg->hooks->gl.glUniform2iv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniform3f: + dbg->hooks->gl.glUniform3f( + static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), + static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glUniform3fv: + dbg->hooks->gl.glUniform3fv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniform3i: + dbg->hooks->gl.glUniform3i( + static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glUniform3iv: + dbg->hooks->gl.glUniform3iv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniform4f: + dbg->hooks->gl.glUniform4f( + static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), + static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()), + static_cast<GLfloat>(cmd.arg4())); + break; + case glesv2debugger::Message_Function_glUniform4fv: + dbg->hooks->gl.glUniform4fv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniform4i: + dbg->hooks->gl.glUniform4i( + static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()), + static_cast<GLint>(cmd.arg4())); + break; + case glesv2debugger::Message_Function_glUniform4iv: + dbg->hooks->gl.glUniform4iv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniformMatrix2fv: + dbg->hooks->gl.glUniformMatrix2fv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniformMatrix3fv: + dbg->hooks->gl.glUniformMatrix3fv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUniformMatrix4fv: + dbg->hooks->gl.glUniformMatrix4fv( + static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), + GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glUseProgram: + dbg->hooks->gl.glUseProgram( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glValidateProgram: + dbg->hooks->gl.glValidateProgram( + static_cast<GLuint>(cmd.arg0())); + break; + case glesv2debugger::Message_Function_glVertexAttrib1f: + dbg->hooks->gl.glVertexAttrib1f( + static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()) + ); + break; + case glesv2debugger::Message_Function_glVertexAttrib1fv: + dbg->hooks->gl.glVertexAttrib1fv( + static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glVertexAttrib2f: + dbg->hooks->gl.glVertexAttrib2f( + static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), + static_cast<GLfloat>(cmd.arg2())); + break; + case glesv2debugger::Message_Function_glVertexAttrib2fv: + dbg->hooks->gl.glVertexAttrib2fv( + static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glVertexAttrib3f: + dbg->hooks->gl.glVertexAttrib3f( + static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), + static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()) + ); + break; + case glesv2debugger::Message_Function_glVertexAttrib3fv: + dbg->hooks->gl.glVertexAttrib3fv( + static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glVertexAttrib4f: + dbg->hooks->gl.glVertexAttrib4f( + static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), + static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()), + static_cast<GLfloat>(cmd.arg4())); + break; + case glesv2debugger::Message_Function_glVertexAttrib4fv: + dbg->hooks->gl.glVertexAttrib4fv( + static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data())) + ); + break; + case glesv2debugger::Message_Function_glVertexAttribPointer: + ret = GenerateCall_glVertexAttribPointer(dbg, cmd, msg, prevRet); + break; + case glesv2debugger::Message_Function_glViewport: + dbg->hooks->gl.glViewport( + static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), + static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3()) + ); + break; + default: + assert(0); + } + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_function(cmd.function()); + msg.set_type(glesv2debugger::Message_Type_AfterCall); + return ret; +} + +}; // name space android { diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h new file mode 100644 index 0000000..5447757 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/caller.h @@ -0,0 +1,320 @@ +/* + ** 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. + */ + +static const int * GenerateCall_glCompressedTexImage2D(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glCompressedTexSubImage2D(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glDrawElements(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGenBuffers(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGenFramebuffers(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGenRenderbuffers(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGenTextures(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetActiveAttrib(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetActiveUniform(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetAttachedShaders(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetBooleanv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetBufferParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetFloatv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetFramebufferAttachmentParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetIntegerv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetRenderbufferParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetShaderPrecisionFormat(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetShaderSource(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetString(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetTexParameterfv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetTexParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetUniformfv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetUniformiv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetVertexAttribfv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetVertexAttribiv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glGetVertexAttribPointerv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glReadPixels(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glShaderBinary(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glShaderSource(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + const char * string = cmd.data().data(); + dbg->hooks->gl.glShaderSource(cmd.arg0(), 1, &string, NULL); + return prevRet; +} + +static const int * GenerateCall_glTexImage2D(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glTexParameterfv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glTexParameteriv(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glTexSubImage2D(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} + +static const int * GenerateCall_glVertexAttribPointer(DbgContext * const dbg, + const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet) +{ + assert(0); + return prevRet; +} diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp new file mode 100644 index 0000000..3ef0752 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp @@ -0,0 +1,333 @@ +/* + ** 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. + */ + +#include "header.h" + +extern "C" +{ +#include "liblzf/lzf.h" +} + +namespace android +{ + +DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks, + const unsigned MAX_VERTEX_ATTRIBS) + : lzf_buf(NULL), lzf_bufSize(0) + , lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0) + , version(version), hooks(hooks) + , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS) + , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS]) + , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL) + , program(0), maxAttrib(0) +{ + lzf_ref[0] = lzf_ref[1] = NULL; + for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++) + vertexAttribs[i] = VertexAttrib(); + memset(&expectResponse, 0, sizeof(expectResponse)); +} + +DbgContext::~DbgContext() +{ + delete vertexAttribs; + free(lzf_buf); + free(lzf_ref[0]); + free(lzf_ref[1]); +} + +DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks) +{ + assert(version < 2); + assert(GL_NO_ERROR == hooks->gl.glGetError()); + GLint MAX_VERTEX_ATTRIBS = 0; + hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS); + return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS); +} + +void DestroyDbgContext(DbgContext * const dbg) +{ + delete dbg; +} + +unsigned GetBytesPerPixel(const GLenum format, const GLenum type) +{ + switch (type) { + case GL_UNSIGNED_SHORT_5_6_5: + return 2; + case GL_UNSIGNED_SHORT_4_4_4_4: + return 2; + case GL_UNSIGNED_SHORT_5_5_5_1: + return 2; + case GL_UNSIGNED_BYTE: + break; + default: + assert(0); + } + + switch (format) { + case GL_ALPHA: + return 1; + case GL_LUMINANCE: + return 1; + break; + case GL_LUMINANCE_ALPHA: + return 2; + case GL_RGB: + return 3; + case GL_RGBA: + return 4; + default: + assert(0); + return 0; + } +} + +void DbgContext::Fetch(const unsigned index, std::string * const data) const +{ + // VBO data is already on client, just send user pointer data + for (unsigned i = 0; i < maxAttrib; i++) { + if (!vertexAttribs[i].enabled) + continue; + if (vertexAttribs[i].buffer > 0) + continue; + const char * ptr = (const char *)vertexAttribs[i].ptr; + ptr += index * vertexAttribs[i].stride; + data->append(ptr, vertexAttribs[i].elemSize); + } +} + +unsigned DbgContext::Compress(const void * in_data, unsigned in_len) +{ + if (lzf_bufSize < in_len * 1.05f) { + lzf_bufSize = in_len * 1.05f; + lzf_buf = (char *)realloc(lzf_buf, lzf_bufSize); + } + unsigned compressedSize = lzf_compress((const char *)in_data, + in_len, lzf_buf, lzf_bufSize); + assert (0 < compressedSize); + return compressedSize; +} + +void * DbgContext::GetReadPixelsBuffer(const unsigned size) +{ + if (lzf_refBufSize < size + 8) { + lzf_refBufSize = size + 8; + lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize); + memset(lzf_ref[0], 0, lzf_refBufSize); + lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize); + memset(lzf_ref[1], 0, lzf_refBufSize); + } + if (lzf_refSize != size) // need to clear unused ref to maintain consistency + { // since ref and src are swapped each time + memset((char *)lzf_ref[0] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize); + memset((char *)lzf_ref[1] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize); + } + lzf_refSize = size; + lzf_readIndex ^= 1; + return lzf_ref[lzf_readIndex]; +} + +unsigned DbgContext::CompressReadPixelBuffer() +{ + unsigned * const ref = lzf_ref[lzf_readIndex ^ 1]; + unsigned * const src = lzf_ref[lzf_readIndex]; + for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++) + ref[i] ^= src[i]; + return Compress(ref, lzf_refSize); +} + +void DbgContext::glUseProgram(GLuint program) +{ + while (GLenum error = hooks->gl.glGetError()) + LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error); + + this->program = program; + + GLint activeAttributes = 0; + hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes); + maxAttrib = 0; + GLint maxNameLen = -1; + hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLen); + char * name = new char [maxNameLen + 1]; + name[maxNameLen] = 0; + // find total number of attribute slots used + for (unsigned i = 0; i < activeAttributes; i++) { + GLint size = -1; + GLenum type = -1; + hooks->gl.glGetActiveAttrib(program, i, maxNameLen + 1, NULL, &size, &type, name); + GLint slot = hooks->gl.glGetAttribLocation(program, name); + assert(slot >= 0); + switch (type) { + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + slot += size; + break; + case GL_FLOAT_MAT2: + slot += size * 2; + break; + case GL_FLOAT_MAT3: + slot += size * 3; + break; + case GL_FLOAT_MAT4: + slot += size * 4; + break; + default: + assert(0); + } + if (slot > maxAttrib) + maxAttrib = slot; + } + delete name; + + while (GLenum error = hooks->gl.glGetError()) + LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error); +} + +static bool HasNonVBOAttribs(const DbgContext * const ctx) +{ + bool need = false; + for (unsigned i = 0; !need && i < ctx->maxAttrib; i++) + if (ctx->vertexAttribs[i].enabled && ctx->vertexAttribs[i].buffer == 0) + need = true; + return need; +} + +void DbgContext::glVertexAttribPointer(GLuint indx, GLint size, GLenum type, + GLboolean normalized, GLsizei stride, const GLvoid* ptr) +{ + assert(GL_NO_ERROR == hooks->gl.glGetError()); + assert(indx < MAX_VERTEX_ATTRIBS); + vertexAttribs[indx].size = size; + vertexAttribs[indx].type = type; + vertexAttribs[indx].normalized = normalized; + switch (type) { + case GL_FLOAT: + vertexAttribs[indx].elemSize = sizeof(GLfloat) * size; + break; + case GL_INT: + case GL_UNSIGNED_INT: + vertexAttribs[indx].elemSize = sizeof(GLint) * size; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + vertexAttribs[indx].elemSize = sizeof(GLshort) * size; + break; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + vertexAttribs[indx].elemSize = sizeof(GLbyte) * size; + break; + default: + assert(0); + } + if (0 == stride) + stride = vertexAttribs[indx].elemSize; + vertexAttribs[indx].stride = stride; + vertexAttribs[indx].ptr = ptr; + hooks->gl.glGetVertexAttribiv(indx, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, + (GLint *)&vertexAttribs[indx].buffer); + hasNonVBOAttribs = HasNonVBOAttribs(this); +} + +void DbgContext::glEnableVertexAttribArray(GLuint index) +{ + assert(index < MAX_VERTEX_ATTRIBS); + vertexAttribs[index].enabled = true; + hasNonVBOAttribs = HasNonVBOAttribs(this); +} + +void DbgContext::glDisableVertexAttribArray(GLuint index) +{ + assert(index < MAX_VERTEX_ATTRIBS); + vertexAttribs[index].enabled = false; + hasNonVBOAttribs = HasNonVBOAttribs(this); +} + +void DbgContext::glBindBuffer(GLenum target, GLuint buffer) +{ + if (GL_ELEMENT_ARRAY_BUFFER != target) + return; + if (0 == buffer) { + indexBuffer = NULL; + return; + } + VBO * b = indexBuffers; + indexBuffer = NULL; + while (b) { + if (b->name == buffer) { + assert(GL_ELEMENT_ARRAY_BUFFER == b->target); + indexBuffer = b; + break; + } + b = b->next; + } + if (!indexBuffer) + indexBuffer = indexBuffers = new VBO(buffer, target, indexBuffers); +} + +void DbgContext::glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +{ + if (GL_ELEMENT_ARRAY_BUFFER != target) + return; + assert(indexBuffer); + assert(size >= 0); + indexBuffer->size = size; + indexBuffer->data = realloc(indexBuffer->data, size); + memcpy(indexBuffer->data, data, size); +} + +void DbgContext::glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +{ + if (GL_ELEMENT_ARRAY_BUFFER != target) + return; + assert(indexBuffer); + assert(size >= 0); + assert(offset >= 0); + assert(offset + size <= indexBuffer->size); + memcpy((char *)indexBuffer->data + offset, data, size); +} + +void DbgContext::glDeleteBuffers(GLsizei n, const GLuint *buffers) +{ + for (unsigned i = 0; i < n; i++) { + for (unsigned j = 0; j < MAX_VERTEX_ATTRIBS; j++) + if (buffers[i] == vertexAttribs[j].buffer) { + vertexAttribs[j].buffer = 0; + vertexAttribs[j].enabled = false; + } + VBO * b = indexBuffers, * previous = NULL; + while (b) { + if (b->name == buffers[i]) { + assert(GL_ELEMENT_ARRAY_BUFFER == b->target); + if (indexBuffer == b) + indexBuffer = NULL; + if (previous) + previous->next = b->next; + else + indexBuffers = b->next; + free(b->data); + delete b; + break; + } + previous = b; + b = b->next; + } + } + hasNonVBOAttribs = HasNonVBOAttribs(this); +} + +}; // namespace android diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp new file mode 100644 index 0000000..046c954 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp @@ -0,0 +1,1377 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + +#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION +#include "debugger_message.pb.h" +#include <google/protobuf/stubs/once.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/wire_format_lite_inl.h> +// @@protoc_insertion_point(includes) + +namespace com { +namespace android { +namespace glesv2debugger { + +void protobuf_ShutdownFile_debugger_5fmessage_2eproto() { + delete Message::default_instance_; +} + +void protobuf_AddDesc_debugger_5fmessage_2eproto() { + static bool already_here = false; + if (already_here) return; + already_here = true; + GOOGLE_PROTOBUF_VERIFY_VERSION; + + Message::default_instance_ = new Message(); + Message::default_instance_->InitAsDefaultInstance(); + ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_debugger_5fmessage_2eproto); +} + +// Force AddDescriptors() to be called at static initialization time. +struct StaticDescriptorInitializer_debugger_5fmessage_2eproto { + StaticDescriptorInitializer_debugger_5fmessage_2eproto() { + protobuf_AddDesc_debugger_5fmessage_2eproto(); + } +} static_descriptor_initializer_debugger_5fmessage_2eproto_; + + +// =================================================================== + +bool Message_Function_IsValid(int value) { + switch(value) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: + case 63: + case 64: + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + case 123: + case 124: + case 125: + case 126: + case 127: + case 128: + case 129: + case 130: + case 131: + case 132: + case 133: + case 134: + case 135: + case 136: + case 137: + case 138: + case 139: + case 140: + case 141: + case 142: + case 143: + case 144: + case 145: + case 146: + case 147: + case 148: + case 149: + case 150: + case 151: + case 152: + case 153: + case 154: + case 155: + case 156: + case 157: + case 158: + case 159: + case 160: + case 161: + case 162: + case 163: + case 164: + case 165: + case 166: + case 167: + case 168: + case 169: + case 170: + case 171: + case 172: + case 173: + case 174: + case 175: + case 176: + case 177: + case 178: + case 179: + case 180: + case 181: + case 182: + case 183: + case 184: + case 185: + case 186: + case 187: + case 188: + case 189: + case 190: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const Message_Function Message::glActiveTexture; +const Message_Function Message::glAttachShader; +const Message_Function Message::glBindAttribLocation; +const Message_Function Message::glBindBuffer; +const Message_Function Message::glBindFramebuffer; +const Message_Function Message::glBindRenderbuffer; +const Message_Function Message::glBindTexture; +const Message_Function Message::glBlendColor; +const Message_Function Message::glBlendEquation; +const Message_Function Message::glBlendEquationSeparate; +const Message_Function Message::glBlendFunc; +const Message_Function Message::glBlendFuncSeparate; +const Message_Function Message::glBufferData; +const Message_Function Message::glBufferSubData; +const Message_Function Message::glCheckFramebufferStatus; +const Message_Function Message::glClear; +const Message_Function Message::glClearColor; +const Message_Function Message::glClearDepthf; +const Message_Function Message::glClearStencil; +const Message_Function Message::glColorMask; +const Message_Function Message::glCompileShader; +const Message_Function Message::glCompressedTexImage2D; +const Message_Function Message::glCompressedTexSubImage2D; +const Message_Function Message::glCopyTexImage2D; +const Message_Function Message::glCopyTexSubImage2D; +const Message_Function Message::glCreateProgram; +const Message_Function Message::glCreateShader; +const Message_Function Message::glCullFace; +const Message_Function Message::glDeleteBuffers; +const Message_Function Message::glDeleteFramebuffers; +const Message_Function Message::glDeleteProgram; +const Message_Function Message::glDeleteRenderbuffers; +const Message_Function Message::glDeleteShader; +const Message_Function Message::glDeleteTextures; +const Message_Function Message::glDepthFunc; +const Message_Function Message::glDepthMask; +const Message_Function Message::glDepthRangef; +const Message_Function Message::glDetachShader; +const Message_Function Message::glDisable; +const Message_Function Message::glDisableVertexAttribArray; +const Message_Function Message::glDrawArrays; +const Message_Function Message::glDrawElements; +const Message_Function Message::glEnable; +const Message_Function Message::glEnableVertexAttribArray; +const Message_Function Message::glFinish; +const Message_Function Message::glFlush; +const Message_Function Message::glFramebufferRenderbuffer; +const Message_Function Message::glFramebufferTexture2D; +const Message_Function Message::glFrontFace; +const Message_Function Message::glGenBuffers; +const Message_Function Message::glGenerateMipmap; +const Message_Function Message::glGenFramebuffers; +const Message_Function Message::glGenRenderbuffers; +const Message_Function Message::glGenTextures; +const Message_Function Message::glGetActiveAttrib; +const Message_Function Message::glGetActiveUniform; +const Message_Function Message::glGetAttachedShaders; +const Message_Function Message::glGetAttribLocation; +const Message_Function Message::glGetBooleanv; +const Message_Function Message::glGetBufferParameteriv; +const Message_Function Message::glGetError; +const Message_Function Message::glGetFloatv; +const Message_Function Message::glGetFramebufferAttachmentParameteriv; +const Message_Function Message::glGetIntegerv; +const Message_Function Message::glGetProgramiv; +const Message_Function Message::glGetProgramInfoLog; +const Message_Function Message::glGetRenderbufferParameteriv; +const Message_Function Message::glGetShaderiv; +const Message_Function Message::glGetShaderInfoLog; +const Message_Function Message::glGetShaderPrecisionFormat; +const Message_Function Message::glGetShaderSource; +const Message_Function Message::glGetString; +const Message_Function Message::glGetTexParameterfv; +const Message_Function Message::glGetTexParameteriv; +const Message_Function Message::glGetUniformfv; +const Message_Function Message::glGetUniformiv; +const Message_Function Message::glGetUniformLocation; +const Message_Function Message::glGetVertexAttribfv; +const Message_Function Message::glGetVertexAttribiv; +const Message_Function Message::glGetVertexAttribPointerv; +const Message_Function Message::glHint; +const Message_Function Message::glIsBuffer; +const Message_Function Message::glIsEnabled; +const Message_Function Message::glIsFramebuffer; +const Message_Function Message::glIsProgram; +const Message_Function Message::glIsRenderbuffer; +const Message_Function Message::glIsShader; +const Message_Function Message::glIsTexture; +const Message_Function Message::glLineWidth; +const Message_Function Message::glLinkProgram; +const Message_Function Message::glPixelStorei; +const Message_Function Message::glPolygonOffset; +const Message_Function Message::glReadPixels; +const Message_Function Message::glReleaseShaderCompiler; +const Message_Function Message::glRenderbufferStorage; +const Message_Function Message::glSampleCoverage; +const Message_Function Message::glScissor; +const Message_Function Message::glShaderBinary; +const Message_Function Message::glShaderSource; +const Message_Function Message::glStencilFunc; +const Message_Function Message::glStencilFuncSeparate; +const Message_Function Message::glStencilMask; +const Message_Function Message::glStencilMaskSeparate; +const Message_Function Message::glStencilOp; +const Message_Function Message::glStencilOpSeparate; +const Message_Function Message::glTexImage2D; +const Message_Function Message::glTexParameterf; +const Message_Function Message::glTexParameterfv; +const Message_Function Message::glTexParameteri; +const Message_Function Message::glTexParameteriv; +const Message_Function Message::glTexSubImage2D; +const Message_Function Message::glUniform1f; +const Message_Function Message::glUniform1fv; +const Message_Function Message::glUniform1i; +const Message_Function Message::glUniform1iv; +const Message_Function Message::glUniform2f; +const Message_Function Message::glUniform2fv; +const Message_Function Message::glUniform2i; +const Message_Function Message::glUniform2iv; +const Message_Function Message::glUniform3f; +const Message_Function Message::glUniform3fv; +const Message_Function Message::glUniform3i; +const Message_Function Message::glUniform3iv; +const Message_Function Message::glUniform4f; +const Message_Function Message::glUniform4fv; +const Message_Function Message::glUniform4i; +const Message_Function Message::glUniform4iv; +const Message_Function Message::glUniformMatrix2fv; +const Message_Function Message::glUniformMatrix3fv; +const Message_Function Message::glUniformMatrix4fv; +const Message_Function Message::glUseProgram; +const Message_Function Message::glValidateProgram; +const Message_Function Message::glVertexAttrib1f; +const Message_Function Message::glVertexAttrib1fv; +const Message_Function Message::glVertexAttrib2f; +const Message_Function Message::glVertexAttrib2fv; +const Message_Function Message::glVertexAttrib3f; +const Message_Function Message::glVertexAttrib3fv; +const Message_Function Message::glVertexAttrib4f; +const Message_Function Message::glVertexAttrib4fv; +const Message_Function Message::glVertexAttribPointer; +const Message_Function Message::glViewport; +const Message_Function Message::eglGetDisplay; +const Message_Function Message::eglInitialize; +const Message_Function Message::eglTerminate; +const Message_Function Message::eglGetConfigs; +const Message_Function Message::eglChooseConfig; +const Message_Function Message::eglGetConfigAttrib; +const Message_Function Message::eglCreateWindowSurface; +const Message_Function Message::eglCreatePixmapSurface; +const Message_Function Message::eglCreatePbufferSurface; +const Message_Function Message::eglDestroySurface; +const Message_Function Message::eglQuerySurface; +const Message_Function Message::eglCreateContext; +const Message_Function Message::eglDestroyContext; +const Message_Function Message::eglMakeCurrent; +const Message_Function Message::eglGetCurrentContext; +const Message_Function Message::eglGetCurrentSurface; +const Message_Function Message::eglGetCurrentDisplay; +const Message_Function Message::eglQueryContext; +const Message_Function Message::eglWaitGL; +const Message_Function Message::eglWaitNative; +const Message_Function Message::eglSwapBuffers; +const Message_Function Message::eglCopyBuffers; +const Message_Function Message::eglGetError; +const Message_Function Message::eglQueryString; +const Message_Function Message::eglGetProcAddress; +const Message_Function Message::eglSurfaceAttrib; +const Message_Function Message::eglBindTexImage; +const Message_Function Message::eglReleaseTexImage; +const Message_Function Message::eglSwapInterval; +const Message_Function Message::eglBindAPI; +const Message_Function Message::eglQueryAPI; +const Message_Function Message::eglWaitClient; +const Message_Function Message::eglReleaseThread; +const Message_Function Message::eglCreatePbufferFromClientBuffer; +const Message_Function Message::eglLockSurfaceKHR; +const Message_Function Message::eglUnlockSurfaceKHR; +const Message_Function Message::eglCreateImageKHR; +const Message_Function Message::eglDestroyImageKHR; +const Message_Function Message::eglCreateSyncKHR; +const Message_Function Message::eglDestroySyncKHR; +const Message_Function Message::eglClientWaitSyncKHR; +const Message_Function Message::eglGetSyncAttribKHR; +const Message_Function Message::eglSetSwapRectangleANDROID; +const Message_Function Message::eglGetRenderBufferANDROID; +const Message_Function Message::ACK; +const Message_Function Message::NEG; +const Message_Function Message::CONTINUE; +const Message_Function Message::SKIP; +const Message_Function Message::SETPROP; +const Message_Function Message::Function_MIN; +const Message_Function Message::Function_MAX; +const int Message::Function_ARRAYSIZE; +#endif // _MSC_VER +bool Message_Type_IsValid(int value) { + switch(value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const Message_Type Message::BeforeCall; +const Message_Type Message::AfterCall; +const Message_Type Message::Response; +const Message_Type Message::Type_MIN; +const Message_Type Message::Type_MAX; +const int Message::Type_ARRAYSIZE; +#endif // _MSC_VER +bool Message_DataType_IsValid(int value) { + switch(value) { + case 0: + case 1: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const Message_DataType Message::ReferencedImage; +const Message_DataType Message::NonreferencedImage; +const Message_DataType Message::DataType_MIN; +const Message_DataType Message::DataType_MAX; +const int Message::DataType_ARRAYSIZE; +#endif // _MSC_VER +bool Message_Prop_IsValid(int value) { + switch(value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const Message_Prop Message::Capture; +const Message_Prop Message::TimeMode; +const Message_Prop Message::ExpectResponse; +const Message_Prop Message::Prop_MIN; +const Message_Prop Message::Prop_MAX; +const int Message::Prop_ARRAYSIZE; +#endif // _MSC_VER +const ::std::string Message::_default_data_; +#ifndef _MSC_VER +const int Message::kContextIdFieldNumber; +const int Message::kFunctionFieldNumber; +const int Message::kTypeFieldNumber; +const int Message::kExpectResponseFieldNumber; +const int Message::kRetFieldNumber; +const int Message::kArg0FieldNumber; +const int Message::kArg1FieldNumber; +const int Message::kArg2FieldNumber; +const int Message::kArg3FieldNumber; +const int Message::kArg4FieldNumber; +const int Message::kArg5FieldNumber; +const int Message::kArg6FieldNumber; +const int Message::kArg7FieldNumber; +const int Message::kArg8FieldNumber; +const int Message::kDataFieldNumber; +const int Message::kDataTypeFieldNumber; +const int Message::kPixelFormatFieldNumber; +const int Message::kPixelTypeFieldNumber; +const int Message::kTimeFieldNumber; +const int Message::kPropFieldNumber; +const int Message::kClockFieldNumber; +#endif // !_MSC_VER + +Message::Message() + : ::google::protobuf::MessageLite() { + SharedCtor(); +} + +void Message::InitAsDefaultInstance() { +} + +Message::Message(const Message& from) + : ::google::protobuf::MessageLite() { + SharedCtor(); + MergeFrom(from); +} + +void Message::SharedCtor() { + _cached_size_ = 0; + context_id_ = 0; + function_ = 187; + type_ = 0; + expect_response_ = false; + ret_ = 0; + arg0_ = 0; + arg1_ = 0; + arg2_ = 0; + arg3_ = 0; + arg4_ = 0; + arg5_ = 0; + arg6_ = 0; + arg7_ = 0; + arg8_ = 0; + data_ = const_cast< ::std::string*>(&_default_data_); + data_type_ = 0; + pixel_format_ = 0; + pixel_type_ = 0; + time_ = 0; + prop_ = 0; + clock_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +Message::~Message() { + SharedDtor(); +} + +void Message::SharedDtor() { + if (data_ != &_default_data_) { + delete data_; + } + if (this != default_instance_) { + } +} + +void Message::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const Message& Message::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_debugger_5fmessage_2eproto(); return *default_instance_; +} + +Message* Message::default_instance_ = NULL; + +Message* Message::New() const { + return new Message; +} + +void Message::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + context_id_ = 0; + function_ = 187; + type_ = 0; + expect_response_ = false; + ret_ = 0; + arg0_ = 0; + arg1_ = 0; + arg2_ = 0; + } + if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { + arg3_ = 0; + arg4_ = 0; + arg5_ = 0; + arg6_ = 0; + arg7_ = 0; + arg8_ = 0; + if (_has_bit(14)) { + if (data_ != &_default_data_) { + data_->clear(); + } + } + data_type_ = 0; + } + if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) { + pixel_format_ = 0; + pixel_type_ = 0; + time_ = 0; + prop_ = 0; + clock_ = 0; + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +bool Message::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // required int32 context_id = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &context_id_))); + _set_bit(0); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_function; + break; + } + + // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG]; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_function: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::com::android::glesv2debugger::Message_Function_IsValid(value)) { + set_function(static_cast< ::com::android::glesv2debugger::Message_Function >(value)); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(24)) goto parse_type; + break; + } + + // required .com.android.glesv2debugger.Message.Type type = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_type: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::com::android::glesv2debugger::Message_Type_IsValid(value)) { + set_type(static_cast< ::com::android::glesv2debugger::Message_Type >(value)); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(32)) goto parse_expect_response; + break; + } + + // required bool expect_response = 4; + case 4: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_expect_response: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &expect_response_))); + _set_bit(3); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(40)) goto parse_ret; + break; + } + + // optional int32 ret = 5; + case 5: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_ret: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &ret_))); + _set_bit(4); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(48)) goto parse_arg0; + break; + } + + // optional int32 arg0 = 6; + case 6: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg0: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg0_))); + _set_bit(5); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(56)) goto parse_arg1; + break; + } + + // optional int32 arg1 = 7; + case 7: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg1: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg1_))); + _set_bit(6); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(64)) goto parse_arg2; + break; + } + + // optional int32 arg2 = 8; + case 8: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg2: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg2_))); + _set_bit(7); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(72)) goto parse_arg3; + break; + } + + // optional int32 arg3 = 9; + case 9: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg3: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg3_))); + _set_bit(8); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(82)) goto parse_data; + break; + } + + // optional bytes data = 10; + case 10: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_data: + DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( + input, this->mutable_data())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(93)) goto parse_time; + break; + } + + // optional float time = 11; + case 11: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) { + parse_time: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>( + input, &time_))); + _set_bit(18); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(128)) goto parse_arg4; + break; + } + + // optional int32 arg4 = 16; + case 16: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg4: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg4_))); + _set_bit(9); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(136)) goto parse_arg5; + break; + } + + // optional int32 arg5 = 17; + case 17: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg5: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg5_))); + _set_bit(10); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(144)) goto parse_arg6; + break; + } + + // optional int32 arg6 = 18; + case 18: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg6: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg6_))); + _set_bit(11); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(152)) goto parse_arg7; + break; + } + + // optional int32 arg7 = 19; + case 19: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg7: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg7_))); + _set_bit(12); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(160)) goto parse_arg8; + break; + } + + // optional int32 arg8 = 20; + case 20: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_arg8: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &arg8_))); + _set_bit(13); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(168)) goto parse_prop; + break; + } + + // optional .com.android.glesv2debugger.Message.Prop prop = 21; + case 21: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_prop: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::com::android::glesv2debugger::Message_Prop_IsValid(value)) { + set_prop(static_cast< ::com::android::glesv2debugger::Message_Prop >(value)); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(181)) goto parse_clock; + break; + } + + // optional float clock = 22; + case 22: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) { + parse_clock: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>( + input, &clock_))); + _set_bit(20); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(184)) goto parse_data_type; + break; + } + + // optional .com.android.glesv2debugger.Message.DataType data_type = 23; + case 23: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_data_type: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::com::android::glesv2debugger::Message_DataType_IsValid(value)) { + set_data_type(static_cast< ::com::android::glesv2debugger::Message_DataType >(value)); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(192)) goto parse_pixel_format; + break; + } + + // optional int32 pixel_format = 24; + case 24: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_pixel_format: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &pixel_format_))); + _set_bit(16); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(200)) goto parse_pixel_type; + break; + } + + // optional int32 pixel_type = 25; + case 25: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_pixel_type: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &pixel_type_))); + _set_bit(17); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); + break; + } + } + } + return true; +#undef DO_ +} + +void Message::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // required int32 context_id = 1; + if (_has_bit(0)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->context_id(), output); + } + + // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG]; + if (_has_bit(1)) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 2, this->function(), output); + } + + // required .com.android.glesv2debugger.Message.Type type = 3; + if (_has_bit(2)) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 3, this->type(), output); + } + + // required bool expect_response = 4; + if (_has_bit(3)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->expect_response(), output); + } + + // optional int32 ret = 5; + if (_has_bit(4)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(5, this->ret(), output); + } + + // optional int32 arg0 = 6; + if (_has_bit(5)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(6, this->arg0(), output); + } + + // optional int32 arg1 = 7; + if (_has_bit(6)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(7, this->arg1(), output); + } + + // optional int32 arg2 = 8; + if (_has_bit(7)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(8, this->arg2(), output); + } + + // optional int32 arg3 = 9; + if (_has_bit(8)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->arg3(), output); + } + + // optional bytes data = 10; + if (_has_bit(14)) { + ::google::protobuf::internal::WireFormatLite::WriteBytes( + 10, this->data(), output); + } + + // optional float time = 11; + if (_has_bit(18)) { + ::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output); + } + + // optional int32 arg4 = 16; + if (_has_bit(9)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(16, this->arg4(), output); + } + + // optional int32 arg5 = 17; + if (_has_bit(10)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(17, this->arg5(), output); + } + + // optional int32 arg6 = 18; + if (_has_bit(11)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(18, this->arg6(), output); + } + + // optional int32 arg7 = 19; + if (_has_bit(12)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(19, this->arg7(), output); + } + + // optional int32 arg8 = 20; + if (_has_bit(13)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(20, this->arg8(), output); + } + + // optional .com.android.glesv2debugger.Message.Prop prop = 21; + if (_has_bit(19)) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 21, this->prop(), output); + } + + // optional float clock = 22; + if (_has_bit(20)) { + ::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output); + } + + // optional .com.android.glesv2debugger.Message.DataType data_type = 23; + if (_has_bit(15)) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 23, this->data_type(), output); + } + + // optional int32 pixel_format = 24; + if (_has_bit(16)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(24, this->pixel_format(), output); + } + + // optional int32 pixel_type = 25; + if (_has_bit(17)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output); + } + +} + +int Message::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // required int32 context_id = 1; + if (has_context_id()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->context_id()); + } + + // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG]; + if (has_function()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->function()); + } + + // required .com.android.glesv2debugger.Message.Type type = 3; + if (has_type()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->type()); + } + + // required bool expect_response = 4; + if (has_expect_response()) { + total_size += 1 + 1; + } + + // optional int32 ret = 5; + if (has_ret()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->ret()); + } + + // optional int32 arg0 = 6; + if (has_arg0()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg0()); + } + + // optional int32 arg1 = 7; + if (has_arg1()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg1()); + } + + // optional int32 arg2 = 8; + if (has_arg2()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg2()); + } + + } + if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { + // optional int32 arg3 = 9; + if (has_arg3()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg3()); + } + + // optional int32 arg4 = 16; + if (has_arg4()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg4()); + } + + // optional int32 arg5 = 17; + if (has_arg5()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg5()); + } + + // optional int32 arg6 = 18; + if (has_arg6()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg6()); + } + + // optional int32 arg7 = 19; + if (has_arg7()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg7()); + } + + // optional int32 arg8 = 20; + if (has_arg8()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->arg8()); + } + + // optional bytes data = 10; + if (has_data()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->data()); + } + + // optional .com.android.glesv2debugger.Message.DataType data_type = 23; + if (has_data_type()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->data_type()); + } + + } + if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) { + // optional int32 pixel_format = 24; + if (has_pixel_format()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->pixel_format()); + } + + // optional int32 pixel_type = 25; + if (has_pixel_type()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->pixel_type()); + } + + // optional float time = 11; + if (has_time()) { + total_size += 1 + 4; + } + + // optional .com.android.glesv2debugger.Message.Prop prop = 21; + if (has_prop()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->prop()); + } + + // optional float clock = 22; + if (has_clock()) { + total_size += 2 + 4; + } + + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void Message::CheckTypeAndMergeFrom( + const ::google::protobuf::MessageLite& from) { + MergeFrom(*::google::protobuf::down_cast<const Message*>(&from)); +} + +void Message::MergeFrom(const Message& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from._has_bit(0)) { + set_context_id(from.context_id()); + } + if (from._has_bit(1)) { + set_function(from.function()); + } + if (from._has_bit(2)) { + set_type(from.type()); + } + if (from._has_bit(3)) { + set_expect_response(from.expect_response()); + } + if (from._has_bit(4)) { + set_ret(from.ret()); + } + if (from._has_bit(5)) { + set_arg0(from.arg0()); + } + if (from._has_bit(6)) { + set_arg1(from.arg1()); + } + if (from._has_bit(7)) { + set_arg2(from.arg2()); + } + } + if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) { + if (from._has_bit(8)) { + set_arg3(from.arg3()); + } + if (from._has_bit(9)) { + set_arg4(from.arg4()); + } + if (from._has_bit(10)) { + set_arg5(from.arg5()); + } + if (from._has_bit(11)) { + set_arg6(from.arg6()); + } + if (from._has_bit(12)) { + set_arg7(from.arg7()); + } + if (from._has_bit(13)) { + set_arg8(from.arg8()); + } + if (from._has_bit(14)) { + set_data(from.data()); + } + if (from._has_bit(15)) { + set_data_type(from.data_type()); + } + } + if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) { + if (from._has_bit(16)) { + set_pixel_format(from.pixel_format()); + } + if (from._has_bit(17)) { + set_pixel_type(from.pixel_type()); + } + if (from._has_bit(18)) { + set_time(from.time()); + } + if (from._has_bit(19)) { + set_prop(from.prop()); + } + if (from._has_bit(20)) { + set_clock(from.clock()); + } + } +} + +void Message::CopyFrom(const Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool Message::IsInitialized() const { + if ((_has_bits_[0] & 0x0000000f) != 0x0000000f) return false; + + return true; +} + +void Message::Swap(Message* other) { + if (other != this) { + std::swap(context_id_, other->context_id_); + std::swap(function_, other->function_); + std::swap(type_, other->type_); + std::swap(expect_response_, other->expect_response_); + std::swap(ret_, other->ret_); + std::swap(arg0_, other->arg0_); + std::swap(arg1_, other->arg1_); + std::swap(arg2_, other->arg2_); + std::swap(arg3_, other->arg3_); + std::swap(arg4_, other->arg4_); + std::swap(arg5_, other->arg5_); + std::swap(arg6_, other->arg6_); + std::swap(arg7_, other->arg7_); + std::swap(arg8_, other->arg8_); + std::swap(data_, other->data_); + std::swap(data_type_, other->data_type_); + std::swap(pixel_format_, other->pixel_format_); + std::swap(pixel_type_, other->pixel_type_); + std::swap(time_, other->time_); + std::swap(prop_, other->prop_); + std::swap(clock_, other->clock_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::std::string Message::GetTypeName() const { + return "com.android.glesv2debugger.Message"; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace glesv2debugger +} // namespace android +} // namespace com + +// @@protoc_insertion_point(global_scope) diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h new file mode 100644 index 0000000..b2ec5a0 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h @@ -0,0 +1,1131 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: debugger_message.proto + +#ifndef PROTOBUF_debugger_5fmessage_2eproto__INCLUDED +#define PROTOBUF_debugger_5fmessage_2eproto__INCLUDED + +#include <string> + +#include <google/protobuf/stubs/common.h> + +#if GOOGLE_PROTOBUF_VERSION < 2003000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 2003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include <google/protobuf/generated_message_util.h> +#include <google/protobuf/repeated_field.h> +#include <google/protobuf/extension_set.h> +// @@protoc_insertion_point(includes) + +namespace com { +namespace android { +namespace glesv2debugger { + +// Internal implementation detail -- do not call these. +void protobuf_AddDesc_debugger_5fmessage_2eproto(); +void protobuf_AssignDesc_debugger_5fmessage_2eproto(); +void protobuf_ShutdownFile_debugger_5fmessage_2eproto(); + +class Message; + +enum Message_Function { + Message_Function_glActiveTexture = 0, + Message_Function_glAttachShader = 1, + Message_Function_glBindAttribLocation = 2, + Message_Function_glBindBuffer = 3, + Message_Function_glBindFramebuffer = 4, + Message_Function_glBindRenderbuffer = 5, + Message_Function_glBindTexture = 6, + Message_Function_glBlendColor = 7, + Message_Function_glBlendEquation = 8, + Message_Function_glBlendEquationSeparate = 9, + Message_Function_glBlendFunc = 10, + Message_Function_glBlendFuncSeparate = 11, + Message_Function_glBufferData = 12, + Message_Function_glBufferSubData = 13, + Message_Function_glCheckFramebufferStatus = 14, + Message_Function_glClear = 15, + Message_Function_glClearColor = 16, + Message_Function_glClearDepthf = 17, + Message_Function_glClearStencil = 18, + Message_Function_glColorMask = 19, + Message_Function_glCompileShader = 20, + Message_Function_glCompressedTexImage2D = 21, + Message_Function_glCompressedTexSubImage2D = 22, + Message_Function_glCopyTexImage2D = 23, + Message_Function_glCopyTexSubImage2D = 24, + Message_Function_glCreateProgram = 25, + Message_Function_glCreateShader = 26, + Message_Function_glCullFace = 27, + Message_Function_glDeleteBuffers = 28, + Message_Function_glDeleteFramebuffers = 29, + Message_Function_glDeleteProgram = 30, + Message_Function_glDeleteRenderbuffers = 31, + Message_Function_glDeleteShader = 32, + Message_Function_glDeleteTextures = 33, + Message_Function_glDepthFunc = 34, + Message_Function_glDepthMask = 35, + Message_Function_glDepthRangef = 36, + Message_Function_glDetachShader = 37, + Message_Function_glDisable = 38, + Message_Function_glDisableVertexAttribArray = 39, + Message_Function_glDrawArrays = 40, + Message_Function_glDrawElements = 41, + Message_Function_glEnable = 42, + Message_Function_glEnableVertexAttribArray = 43, + Message_Function_glFinish = 44, + Message_Function_glFlush = 45, + Message_Function_glFramebufferRenderbuffer = 46, + Message_Function_glFramebufferTexture2D = 47, + Message_Function_glFrontFace = 48, + Message_Function_glGenBuffers = 49, + Message_Function_glGenerateMipmap = 50, + Message_Function_glGenFramebuffers = 51, + Message_Function_glGenRenderbuffers = 52, + Message_Function_glGenTextures = 53, + Message_Function_glGetActiveAttrib = 54, + Message_Function_glGetActiveUniform = 55, + Message_Function_glGetAttachedShaders = 56, + Message_Function_glGetAttribLocation = 57, + Message_Function_glGetBooleanv = 58, + Message_Function_glGetBufferParameteriv = 59, + Message_Function_glGetError = 60, + Message_Function_glGetFloatv = 61, + Message_Function_glGetFramebufferAttachmentParameteriv = 62, + Message_Function_glGetIntegerv = 63, + Message_Function_glGetProgramiv = 64, + Message_Function_glGetProgramInfoLog = 65, + Message_Function_glGetRenderbufferParameteriv = 66, + Message_Function_glGetShaderiv = 67, + Message_Function_glGetShaderInfoLog = 68, + Message_Function_glGetShaderPrecisionFormat = 69, + Message_Function_glGetShaderSource = 70, + Message_Function_glGetString = 71, + Message_Function_glGetTexParameterfv = 72, + Message_Function_glGetTexParameteriv = 73, + Message_Function_glGetUniformfv = 74, + Message_Function_glGetUniformiv = 75, + Message_Function_glGetUniformLocation = 76, + Message_Function_glGetVertexAttribfv = 77, + Message_Function_glGetVertexAttribiv = 78, + Message_Function_glGetVertexAttribPointerv = 79, + Message_Function_glHint = 80, + Message_Function_glIsBuffer = 81, + Message_Function_glIsEnabled = 82, + Message_Function_glIsFramebuffer = 83, + Message_Function_glIsProgram = 84, + Message_Function_glIsRenderbuffer = 85, + Message_Function_glIsShader = 86, + Message_Function_glIsTexture = 87, + Message_Function_glLineWidth = 88, + Message_Function_glLinkProgram = 89, + Message_Function_glPixelStorei = 90, + Message_Function_glPolygonOffset = 91, + Message_Function_glReadPixels = 92, + Message_Function_glReleaseShaderCompiler = 93, + Message_Function_glRenderbufferStorage = 94, + Message_Function_glSampleCoverage = 95, + Message_Function_glScissor = 96, + Message_Function_glShaderBinary = 97, + Message_Function_glShaderSource = 98, + Message_Function_glStencilFunc = 99, + Message_Function_glStencilFuncSeparate = 100, + Message_Function_glStencilMask = 101, + Message_Function_glStencilMaskSeparate = 102, + Message_Function_glStencilOp = 103, + Message_Function_glStencilOpSeparate = 104, + Message_Function_glTexImage2D = 105, + Message_Function_glTexParameterf = 106, + Message_Function_glTexParameterfv = 107, + Message_Function_glTexParameteri = 108, + Message_Function_glTexParameteriv = 109, + Message_Function_glTexSubImage2D = 110, + Message_Function_glUniform1f = 111, + Message_Function_glUniform1fv = 112, + Message_Function_glUniform1i = 113, + Message_Function_glUniform1iv = 114, + Message_Function_glUniform2f = 115, + Message_Function_glUniform2fv = 116, + Message_Function_glUniform2i = 117, + Message_Function_glUniform2iv = 118, + Message_Function_glUniform3f = 119, + Message_Function_glUniform3fv = 120, + Message_Function_glUniform3i = 121, + Message_Function_glUniform3iv = 122, + Message_Function_glUniform4f = 123, + Message_Function_glUniform4fv = 124, + Message_Function_glUniform4i = 125, + Message_Function_glUniform4iv = 126, + Message_Function_glUniformMatrix2fv = 127, + Message_Function_glUniformMatrix3fv = 128, + Message_Function_glUniformMatrix4fv = 129, + Message_Function_glUseProgram = 130, + Message_Function_glValidateProgram = 131, + Message_Function_glVertexAttrib1f = 132, + Message_Function_glVertexAttrib1fv = 133, + Message_Function_glVertexAttrib2f = 134, + Message_Function_glVertexAttrib2fv = 135, + Message_Function_glVertexAttrib3f = 136, + Message_Function_glVertexAttrib3fv = 137, + Message_Function_glVertexAttrib4f = 138, + Message_Function_glVertexAttrib4fv = 139, + Message_Function_glVertexAttribPointer = 140, + Message_Function_glViewport = 141, + Message_Function_eglGetDisplay = 142, + Message_Function_eglInitialize = 143, + Message_Function_eglTerminate = 144, + Message_Function_eglGetConfigs = 145, + Message_Function_eglChooseConfig = 146, + Message_Function_eglGetConfigAttrib = 147, + Message_Function_eglCreateWindowSurface = 148, + Message_Function_eglCreatePixmapSurface = 149, + Message_Function_eglCreatePbufferSurface = 150, + Message_Function_eglDestroySurface = 151, + Message_Function_eglQuerySurface = 152, + Message_Function_eglCreateContext = 153, + Message_Function_eglDestroyContext = 154, + Message_Function_eglMakeCurrent = 155, + Message_Function_eglGetCurrentContext = 156, + Message_Function_eglGetCurrentSurface = 157, + Message_Function_eglGetCurrentDisplay = 158, + Message_Function_eglQueryContext = 159, + Message_Function_eglWaitGL = 160, + Message_Function_eglWaitNative = 161, + Message_Function_eglSwapBuffers = 162, + Message_Function_eglCopyBuffers = 163, + Message_Function_eglGetError = 164, + Message_Function_eglQueryString = 165, + Message_Function_eglGetProcAddress = 166, + Message_Function_eglSurfaceAttrib = 167, + Message_Function_eglBindTexImage = 168, + Message_Function_eglReleaseTexImage = 169, + Message_Function_eglSwapInterval = 170, + Message_Function_eglBindAPI = 171, + Message_Function_eglQueryAPI = 172, + Message_Function_eglWaitClient = 173, + Message_Function_eglReleaseThread = 174, + Message_Function_eglCreatePbufferFromClientBuffer = 175, + Message_Function_eglLockSurfaceKHR = 176, + Message_Function_eglUnlockSurfaceKHR = 177, + Message_Function_eglCreateImageKHR = 178, + Message_Function_eglDestroyImageKHR = 179, + Message_Function_eglCreateSyncKHR = 180, + Message_Function_eglDestroySyncKHR = 181, + Message_Function_eglClientWaitSyncKHR = 182, + Message_Function_eglGetSyncAttribKHR = 183, + Message_Function_eglSetSwapRectangleANDROID = 184, + Message_Function_eglGetRenderBufferANDROID = 185, + Message_Function_ACK = 186, + Message_Function_NEG = 187, + Message_Function_CONTINUE = 188, + Message_Function_SKIP = 189, + Message_Function_SETPROP = 190 +}; +bool Message_Function_IsValid(int value); +const Message_Function Message_Function_Function_MIN = Message_Function_glActiveTexture; +const Message_Function Message_Function_Function_MAX = Message_Function_SETPROP; +const int Message_Function_Function_ARRAYSIZE = Message_Function_Function_MAX + 1; + +enum Message_Type { + Message_Type_BeforeCall = 0, + Message_Type_AfterCall = 1, + Message_Type_Response = 2 +}; +bool Message_Type_IsValid(int value); +const Message_Type Message_Type_Type_MIN = Message_Type_BeforeCall; +const Message_Type Message_Type_Type_MAX = Message_Type_Response; +const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1; + +enum Message_DataType { + Message_DataType_ReferencedImage = 0, + Message_DataType_NonreferencedImage = 1 +}; +bool Message_DataType_IsValid(int value); +const Message_DataType Message_DataType_DataType_MIN = Message_DataType_ReferencedImage; +const Message_DataType Message_DataType_DataType_MAX = Message_DataType_NonreferencedImage; +const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1; + +enum Message_Prop { + Message_Prop_Capture = 0, + Message_Prop_TimeMode = 1, + Message_Prop_ExpectResponse = 2 +}; +bool Message_Prop_IsValid(int value); +const Message_Prop Message_Prop_Prop_MIN = Message_Prop_Capture; +const Message_Prop Message_Prop_Prop_MAX = Message_Prop_ExpectResponse; +const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1; + +// =================================================================== + +class Message : public ::google::protobuf::MessageLite { + public: + Message(); + virtual ~Message(); + + Message(const Message& from); + + inline Message& operator=(const Message& from) { + CopyFrom(from); + return *this; + } + + static const Message& default_instance(); + + void Swap(Message* other); + + // implements Message ---------------------------------------------- + + Message* New() const; + void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); + void CopyFrom(const Message& from); + void MergeFrom(const Message& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::std::string GetTypeName() const; + + // nested types ---------------------------------------------------- + + typedef Message_Function Function; + static const Function glActiveTexture = Message_Function_glActiveTexture; + static const Function glAttachShader = Message_Function_glAttachShader; + static const Function glBindAttribLocation = Message_Function_glBindAttribLocation; + static const Function glBindBuffer = Message_Function_glBindBuffer; + static const Function glBindFramebuffer = Message_Function_glBindFramebuffer; + static const Function glBindRenderbuffer = Message_Function_glBindRenderbuffer; + static const Function glBindTexture = Message_Function_glBindTexture; + static const Function glBlendColor = Message_Function_glBlendColor; + static const Function glBlendEquation = Message_Function_glBlendEquation; + static const Function glBlendEquationSeparate = Message_Function_glBlendEquationSeparate; + static const Function glBlendFunc = Message_Function_glBlendFunc; + static const Function glBlendFuncSeparate = Message_Function_glBlendFuncSeparate; + static const Function glBufferData = Message_Function_glBufferData; + static const Function glBufferSubData = Message_Function_glBufferSubData; + static const Function glCheckFramebufferStatus = Message_Function_glCheckFramebufferStatus; + static const Function glClear = Message_Function_glClear; + static const Function glClearColor = Message_Function_glClearColor; + static const Function glClearDepthf = Message_Function_glClearDepthf; + static const Function glClearStencil = Message_Function_glClearStencil; + static const Function glColorMask = Message_Function_glColorMask; + static const Function glCompileShader = Message_Function_glCompileShader; + static const Function glCompressedTexImage2D = Message_Function_glCompressedTexImage2D; + static const Function glCompressedTexSubImage2D = Message_Function_glCompressedTexSubImage2D; + static const Function glCopyTexImage2D = Message_Function_glCopyTexImage2D; + static const Function glCopyTexSubImage2D = Message_Function_glCopyTexSubImage2D; + static const Function glCreateProgram = Message_Function_glCreateProgram; + static const Function glCreateShader = Message_Function_glCreateShader; + static const Function glCullFace = Message_Function_glCullFace; + static const Function glDeleteBuffers = Message_Function_glDeleteBuffers; + static const Function glDeleteFramebuffers = Message_Function_glDeleteFramebuffers; + static const Function glDeleteProgram = Message_Function_glDeleteProgram; + static const Function glDeleteRenderbuffers = Message_Function_glDeleteRenderbuffers; + static const Function glDeleteShader = Message_Function_glDeleteShader; + static const Function glDeleteTextures = Message_Function_glDeleteTextures; + static const Function glDepthFunc = Message_Function_glDepthFunc; + static const Function glDepthMask = Message_Function_glDepthMask; + static const Function glDepthRangef = Message_Function_glDepthRangef; + static const Function glDetachShader = Message_Function_glDetachShader; + static const Function glDisable = Message_Function_glDisable; + static const Function glDisableVertexAttribArray = Message_Function_glDisableVertexAttribArray; + static const Function glDrawArrays = Message_Function_glDrawArrays; + static const Function glDrawElements = Message_Function_glDrawElements; + static const Function glEnable = Message_Function_glEnable; + static const Function glEnableVertexAttribArray = Message_Function_glEnableVertexAttribArray; + static const Function glFinish = Message_Function_glFinish; + static const Function glFlush = Message_Function_glFlush; + static const Function glFramebufferRenderbuffer = Message_Function_glFramebufferRenderbuffer; + static const Function glFramebufferTexture2D = Message_Function_glFramebufferTexture2D; + static const Function glFrontFace = Message_Function_glFrontFace; + static const Function glGenBuffers = Message_Function_glGenBuffers; + static const Function glGenerateMipmap = Message_Function_glGenerateMipmap; + static const Function glGenFramebuffers = Message_Function_glGenFramebuffers; + static const Function glGenRenderbuffers = Message_Function_glGenRenderbuffers; + static const Function glGenTextures = Message_Function_glGenTextures; + static const Function glGetActiveAttrib = Message_Function_glGetActiveAttrib; + static const Function glGetActiveUniform = Message_Function_glGetActiveUniform; + static const Function glGetAttachedShaders = Message_Function_glGetAttachedShaders; + static const Function glGetAttribLocation = Message_Function_glGetAttribLocation; + static const Function glGetBooleanv = Message_Function_glGetBooleanv; + static const Function glGetBufferParameteriv = Message_Function_glGetBufferParameteriv; + static const Function glGetError = Message_Function_glGetError; + static const Function glGetFloatv = Message_Function_glGetFloatv; + static const Function glGetFramebufferAttachmentParameteriv = Message_Function_glGetFramebufferAttachmentParameteriv; + static const Function glGetIntegerv = Message_Function_glGetIntegerv; + static const Function glGetProgramiv = Message_Function_glGetProgramiv; + static const Function glGetProgramInfoLog = Message_Function_glGetProgramInfoLog; + static const Function glGetRenderbufferParameteriv = Message_Function_glGetRenderbufferParameteriv; + static const Function glGetShaderiv = Message_Function_glGetShaderiv; + static const Function glGetShaderInfoLog = Message_Function_glGetShaderInfoLog; + static const Function glGetShaderPrecisionFormat = Message_Function_glGetShaderPrecisionFormat; + static const Function glGetShaderSource = Message_Function_glGetShaderSource; + static const Function glGetString = Message_Function_glGetString; + static const Function glGetTexParameterfv = Message_Function_glGetTexParameterfv; + static const Function glGetTexParameteriv = Message_Function_glGetTexParameteriv; + static const Function glGetUniformfv = Message_Function_glGetUniformfv; + static const Function glGetUniformiv = Message_Function_glGetUniformiv; + static const Function glGetUniformLocation = Message_Function_glGetUniformLocation; + static const Function glGetVertexAttribfv = Message_Function_glGetVertexAttribfv; + static const Function glGetVertexAttribiv = Message_Function_glGetVertexAttribiv; + static const Function glGetVertexAttribPointerv = Message_Function_glGetVertexAttribPointerv; + static const Function glHint = Message_Function_glHint; + static const Function glIsBuffer = Message_Function_glIsBuffer; + static const Function glIsEnabled = Message_Function_glIsEnabled; + static const Function glIsFramebuffer = Message_Function_glIsFramebuffer; + static const Function glIsProgram = Message_Function_glIsProgram; + static const Function glIsRenderbuffer = Message_Function_glIsRenderbuffer; + static const Function glIsShader = Message_Function_glIsShader; + static const Function glIsTexture = Message_Function_glIsTexture; + static const Function glLineWidth = Message_Function_glLineWidth; + static const Function glLinkProgram = Message_Function_glLinkProgram; + static const Function glPixelStorei = Message_Function_glPixelStorei; + static const Function glPolygonOffset = Message_Function_glPolygonOffset; + static const Function glReadPixels = Message_Function_glReadPixels; + static const Function glReleaseShaderCompiler = Message_Function_glReleaseShaderCompiler; + static const Function glRenderbufferStorage = Message_Function_glRenderbufferStorage; + static const Function glSampleCoverage = Message_Function_glSampleCoverage; + static const Function glScissor = Message_Function_glScissor; + static const Function glShaderBinary = Message_Function_glShaderBinary; + static const Function glShaderSource = Message_Function_glShaderSource; + static const Function glStencilFunc = Message_Function_glStencilFunc; + static const Function glStencilFuncSeparate = Message_Function_glStencilFuncSeparate; + static const Function glStencilMask = Message_Function_glStencilMask; + static const Function glStencilMaskSeparate = Message_Function_glStencilMaskSeparate; + static const Function glStencilOp = Message_Function_glStencilOp; + static const Function glStencilOpSeparate = Message_Function_glStencilOpSeparate; + static const Function glTexImage2D = Message_Function_glTexImage2D; + static const Function glTexParameterf = Message_Function_glTexParameterf; + static const Function glTexParameterfv = Message_Function_glTexParameterfv; + static const Function glTexParameteri = Message_Function_glTexParameteri; + static const Function glTexParameteriv = Message_Function_glTexParameteriv; + static const Function glTexSubImage2D = Message_Function_glTexSubImage2D; + static const Function glUniform1f = Message_Function_glUniform1f; + static const Function glUniform1fv = Message_Function_glUniform1fv; + static const Function glUniform1i = Message_Function_glUniform1i; + static const Function glUniform1iv = Message_Function_glUniform1iv; + static const Function glUniform2f = Message_Function_glUniform2f; + static const Function glUniform2fv = Message_Function_glUniform2fv; + static const Function glUniform2i = Message_Function_glUniform2i; + static const Function glUniform2iv = Message_Function_glUniform2iv; + static const Function glUniform3f = Message_Function_glUniform3f; + static const Function glUniform3fv = Message_Function_glUniform3fv; + static const Function glUniform3i = Message_Function_glUniform3i; + static const Function glUniform3iv = Message_Function_glUniform3iv; + static const Function glUniform4f = Message_Function_glUniform4f; + static const Function glUniform4fv = Message_Function_glUniform4fv; + static const Function glUniform4i = Message_Function_glUniform4i; + static const Function glUniform4iv = Message_Function_glUniform4iv; + static const Function glUniformMatrix2fv = Message_Function_glUniformMatrix2fv; + static const Function glUniformMatrix3fv = Message_Function_glUniformMatrix3fv; + static const Function glUniformMatrix4fv = Message_Function_glUniformMatrix4fv; + static const Function glUseProgram = Message_Function_glUseProgram; + static const Function glValidateProgram = Message_Function_glValidateProgram; + static const Function glVertexAttrib1f = Message_Function_glVertexAttrib1f; + static const Function glVertexAttrib1fv = Message_Function_glVertexAttrib1fv; + static const Function glVertexAttrib2f = Message_Function_glVertexAttrib2f; + static const Function glVertexAttrib2fv = Message_Function_glVertexAttrib2fv; + static const Function glVertexAttrib3f = Message_Function_glVertexAttrib3f; + static const Function glVertexAttrib3fv = Message_Function_glVertexAttrib3fv; + static const Function glVertexAttrib4f = Message_Function_glVertexAttrib4f; + static const Function glVertexAttrib4fv = Message_Function_glVertexAttrib4fv; + static const Function glVertexAttribPointer = Message_Function_glVertexAttribPointer; + static const Function glViewport = Message_Function_glViewport; + static const Function eglGetDisplay = Message_Function_eglGetDisplay; + static const Function eglInitialize = Message_Function_eglInitialize; + static const Function eglTerminate = Message_Function_eglTerminate; + static const Function eglGetConfigs = Message_Function_eglGetConfigs; + static const Function eglChooseConfig = Message_Function_eglChooseConfig; + static const Function eglGetConfigAttrib = Message_Function_eglGetConfigAttrib; + static const Function eglCreateWindowSurface = Message_Function_eglCreateWindowSurface; + static const Function eglCreatePixmapSurface = Message_Function_eglCreatePixmapSurface; + static const Function eglCreatePbufferSurface = Message_Function_eglCreatePbufferSurface; + static const Function eglDestroySurface = Message_Function_eglDestroySurface; + static const Function eglQuerySurface = Message_Function_eglQuerySurface; + static const Function eglCreateContext = Message_Function_eglCreateContext; + static const Function eglDestroyContext = Message_Function_eglDestroyContext; + static const Function eglMakeCurrent = Message_Function_eglMakeCurrent; + static const Function eglGetCurrentContext = Message_Function_eglGetCurrentContext; + static const Function eglGetCurrentSurface = Message_Function_eglGetCurrentSurface; + static const Function eglGetCurrentDisplay = Message_Function_eglGetCurrentDisplay; + static const Function eglQueryContext = Message_Function_eglQueryContext; + static const Function eglWaitGL = Message_Function_eglWaitGL; + static const Function eglWaitNative = Message_Function_eglWaitNative; + static const Function eglSwapBuffers = Message_Function_eglSwapBuffers; + static const Function eglCopyBuffers = Message_Function_eglCopyBuffers; + static const Function eglGetError = Message_Function_eglGetError; + static const Function eglQueryString = Message_Function_eglQueryString; + static const Function eglGetProcAddress = Message_Function_eglGetProcAddress; + static const Function eglSurfaceAttrib = Message_Function_eglSurfaceAttrib; + static const Function eglBindTexImage = Message_Function_eglBindTexImage; + static const Function eglReleaseTexImage = Message_Function_eglReleaseTexImage; + static const Function eglSwapInterval = Message_Function_eglSwapInterval; + static const Function eglBindAPI = Message_Function_eglBindAPI; + static const Function eglQueryAPI = Message_Function_eglQueryAPI; + static const Function eglWaitClient = Message_Function_eglWaitClient; + static const Function eglReleaseThread = Message_Function_eglReleaseThread; + static const Function eglCreatePbufferFromClientBuffer = Message_Function_eglCreatePbufferFromClientBuffer; + static const Function eglLockSurfaceKHR = Message_Function_eglLockSurfaceKHR; + static const Function eglUnlockSurfaceKHR = Message_Function_eglUnlockSurfaceKHR; + static const Function eglCreateImageKHR = Message_Function_eglCreateImageKHR; + static const Function eglDestroyImageKHR = Message_Function_eglDestroyImageKHR; + static const Function eglCreateSyncKHR = Message_Function_eglCreateSyncKHR; + static const Function eglDestroySyncKHR = Message_Function_eglDestroySyncKHR; + static const Function eglClientWaitSyncKHR = Message_Function_eglClientWaitSyncKHR; + static const Function eglGetSyncAttribKHR = Message_Function_eglGetSyncAttribKHR; + static const Function eglSetSwapRectangleANDROID = Message_Function_eglSetSwapRectangleANDROID; + static const Function eglGetRenderBufferANDROID = Message_Function_eglGetRenderBufferANDROID; + static const Function ACK = Message_Function_ACK; + static const Function NEG = Message_Function_NEG; + static const Function CONTINUE = Message_Function_CONTINUE; + static const Function SKIP = Message_Function_SKIP; + static const Function SETPROP = Message_Function_SETPROP; + static inline bool Function_IsValid(int value) { + return Message_Function_IsValid(value); + } + static const Function Function_MIN = + Message_Function_Function_MIN; + static const Function Function_MAX = + Message_Function_Function_MAX; + static const int Function_ARRAYSIZE = + Message_Function_Function_ARRAYSIZE; + + typedef Message_Type Type; + static const Type BeforeCall = Message_Type_BeforeCall; + static const Type AfterCall = Message_Type_AfterCall; + static const Type Response = Message_Type_Response; + static inline bool Type_IsValid(int value) { + return Message_Type_IsValid(value); + } + static const Type Type_MIN = + Message_Type_Type_MIN; + static const Type Type_MAX = + Message_Type_Type_MAX; + static const int Type_ARRAYSIZE = + Message_Type_Type_ARRAYSIZE; + + typedef Message_DataType DataType; + static const DataType ReferencedImage = Message_DataType_ReferencedImage; + static const DataType NonreferencedImage = Message_DataType_NonreferencedImage; + static inline bool DataType_IsValid(int value) { + return Message_DataType_IsValid(value); + } + static const DataType DataType_MIN = + Message_DataType_DataType_MIN; + static const DataType DataType_MAX = + Message_DataType_DataType_MAX; + static const int DataType_ARRAYSIZE = + Message_DataType_DataType_ARRAYSIZE; + + typedef Message_Prop Prop; + static const Prop Capture = Message_Prop_Capture; + static const Prop TimeMode = Message_Prop_TimeMode; + static const Prop ExpectResponse = Message_Prop_ExpectResponse; + static inline bool Prop_IsValid(int value) { + return Message_Prop_IsValid(value); + } + static const Prop Prop_MIN = + Message_Prop_Prop_MIN; + static const Prop Prop_MAX = + Message_Prop_Prop_MAX; + static const int Prop_ARRAYSIZE = + Message_Prop_Prop_ARRAYSIZE; + + // accessors ------------------------------------------------------- + + // required int32 context_id = 1; + inline bool has_context_id() const; + inline void clear_context_id(); + static const int kContextIdFieldNumber = 1; + inline ::google::protobuf::int32 context_id() const; + inline void set_context_id(::google::protobuf::int32 value); + + // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG]; + inline bool has_function() const; + inline void clear_function(); + static const int kFunctionFieldNumber = 2; + inline ::com::android::glesv2debugger::Message_Function function() const; + inline void set_function(::com::android::glesv2debugger::Message_Function value); + + // required .com.android.glesv2debugger.Message.Type type = 3; + inline bool has_type() const; + inline void clear_type(); + static const int kTypeFieldNumber = 3; + inline ::com::android::glesv2debugger::Message_Type type() const; + inline void set_type(::com::android::glesv2debugger::Message_Type value); + + // required bool expect_response = 4; + inline bool has_expect_response() const; + inline void clear_expect_response(); + static const int kExpectResponseFieldNumber = 4; + inline bool expect_response() const; + inline void set_expect_response(bool value); + + // optional int32 ret = 5; + inline bool has_ret() const; + inline void clear_ret(); + static const int kRetFieldNumber = 5; + inline ::google::protobuf::int32 ret() const; + inline void set_ret(::google::protobuf::int32 value); + + // optional int32 arg0 = 6; + inline bool has_arg0() const; + inline void clear_arg0(); + static const int kArg0FieldNumber = 6; + inline ::google::protobuf::int32 arg0() const; + inline void set_arg0(::google::protobuf::int32 value); + + // optional int32 arg1 = 7; + inline bool has_arg1() const; + inline void clear_arg1(); + static const int kArg1FieldNumber = 7; + inline ::google::protobuf::int32 arg1() const; + inline void set_arg1(::google::protobuf::int32 value); + + // optional int32 arg2 = 8; + inline bool has_arg2() const; + inline void clear_arg2(); + static const int kArg2FieldNumber = 8; + inline ::google::protobuf::int32 arg2() const; + inline void set_arg2(::google::protobuf::int32 value); + + // optional int32 arg3 = 9; + inline bool has_arg3() const; + inline void clear_arg3(); + static const int kArg3FieldNumber = 9; + inline ::google::protobuf::int32 arg3() const; + inline void set_arg3(::google::protobuf::int32 value); + + // optional int32 arg4 = 16; + inline bool has_arg4() const; + inline void clear_arg4(); + static const int kArg4FieldNumber = 16; + inline ::google::protobuf::int32 arg4() const; + inline void set_arg4(::google::protobuf::int32 value); + + // optional int32 arg5 = 17; + inline bool has_arg5() const; + inline void clear_arg5(); + static const int kArg5FieldNumber = 17; + inline ::google::protobuf::int32 arg5() const; + inline void set_arg5(::google::protobuf::int32 value); + + // optional int32 arg6 = 18; + inline bool has_arg6() const; + inline void clear_arg6(); + static const int kArg6FieldNumber = 18; + inline ::google::protobuf::int32 arg6() const; + inline void set_arg6(::google::protobuf::int32 value); + + // optional int32 arg7 = 19; + inline bool has_arg7() const; + inline void clear_arg7(); + static const int kArg7FieldNumber = 19; + inline ::google::protobuf::int32 arg7() const; + inline void set_arg7(::google::protobuf::int32 value); + + // optional int32 arg8 = 20; + inline bool has_arg8() const; + inline void clear_arg8(); + static const int kArg8FieldNumber = 20; + inline ::google::protobuf::int32 arg8() const; + inline void set_arg8(::google::protobuf::int32 value); + + // optional bytes data = 10; + inline bool has_data() const; + inline void clear_data(); + static const int kDataFieldNumber = 10; + inline const ::std::string& data() const; + inline void set_data(const ::std::string& value); + inline void set_data(const char* value); + inline void set_data(const void* value, size_t size); + inline ::std::string* mutable_data(); + + // optional .com.android.glesv2debugger.Message.DataType data_type = 23; + inline bool has_data_type() const; + inline void clear_data_type(); + static const int kDataTypeFieldNumber = 23; + inline ::com::android::glesv2debugger::Message_DataType data_type() const; + inline void set_data_type(::com::android::glesv2debugger::Message_DataType value); + + // optional int32 pixel_format = 24; + inline bool has_pixel_format() const; + inline void clear_pixel_format(); + static const int kPixelFormatFieldNumber = 24; + inline ::google::protobuf::int32 pixel_format() const; + inline void set_pixel_format(::google::protobuf::int32 value); + + // optional int32 pixel_type = 25; + inline bool has_pixel_type() const; + inline void clear_pixel_type(); + static const int kPixelTypeFieldNumber = 25; + inline ::google::protobuf::int32 pixel_type() const; + inline void set_pixel_type(::google::protobuf::int32 value); + + // optional float time = 11; + inline bool has_time() const; + inline void clear_time(); + static const int kTimeFieldNumber = 11; + inline float time() const; + inline void set_time(float value); + + // optional .com.android.glesv2debugger.Message.Prop prop = 21; + inline bool has_prop() const; + inline void clear_prop(); + static const int kPropFieldNumber = 21; + inline ::com::android::glesv2debugger::Message_Prop prop() const; + inline void set_prop(::com::android::glesv2debugger::Message_Prop value); + + // optional float clock = 22; + inline bool has_clock() const; + inline void clear_clock(); + static const int kClockFieldNumber = 22; + inline float clock() const; + inline void set_clock(float value); + + // @@protoc_insertion_point(class_scope:com.android.glesv2debugger.Message) + private: + mutable int _cached_size_; + + ::google::protobuf::int32 context_id_; + int function_; + int type_; + bool expect_response_; + ::google::protobuf::int32 ret_; + ::google::protobuf::int32 arg0_; + ::google::protobuf::int32 arg1_; + ::google::protobuf::int32 arg2_; + ::google::protobuf::int32 arg3_; + ::google::protobuf::int32 arg4_; + ::google::protobuf::int32 arg5_; + ::google::protobuf::int32 arg6_; + ::google::protobuf::int32 arg7_; + ::google::protobuf::int32 arg8_; + ::std::string* data_; + static const ::std::string _default_data_; + int data_type_; + ::google::protobuf::int32 pixel_format_; + ::google::protobuf::int32 pixel_type_; + float time_; + int prop_; + float clock_; + friend void protobuf_AddDesc_debugger_5fmessage_2eproto(); + friend void protobuf_AssignDesc_debugger_5fmessage_2eproto(); + friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto(); + + ::google::protobuf::uint32 _has_bits_[(21 + 31) / 32]; + + // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? + inline bool _has_bit(int index) const { + return (_has_bits_[index / 32] & (1u << (index % 32))) != 0; + } + inline void _set_bit(int index) { + _has_bits_[index / 32] |= (1u << (index % 32)); + } + inline void _clear_bit(int index) { + _has_bits_[index / 32] &= ~(1u << (index % 32)); + } + + void InitAsDefaultInstance(); + static Message* default_instance_; +}; +// =================================================================== + + +// =================================================================== + +// Message + +// required int32 context_id = 1; +inline bool Message::has_context_id() const { + return _has_bit(0); +} +inline void Message::clear_context_id() { + context_id_ = 0; + _clear_bit(0); +} +inline ::google::protobuf::int32 Message::context_id() const { + return context_id_; +} +inline void Message::set_context_id(::google::protobuf::int32 value) { + _set_bit(0); + context_id_ = value; +} + +// required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG]; +inline bool Message::has_function() const { + return _has_bit(1); +} +inline void Message::clear_function() { + function_ = 187; + _clear_bit(1); +} +inline ::com::android::glesv2debugger::Message_Function Message::function() const { + return static_cast< ::com::android::glesv2debugger::Message_Function >(function_); +} +inline void Message::set_function(::com::android::glesv2debugger::Message_Function value) { + GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Function_IsValid(value)); + _set_bit(1); + function_ = value; +} + +// required .com.android.glesv2debugger.Message.Type type = 3; +inline bool Message::has_type() const { + return _has_bit(2); +} +inline void Message::clear_type() { + type_ = 0; + _clear_bit(2); +} +inline ::com::android::glesv2debugger::Message_Type Message::type() const { + return static_cast< ::com::android::glesv2debugger::Message_Type >(type_); +} +inline void Message::set_type(::com::android::glesv2debugger::Message_Type value) { + GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Type_IsValid(value)); + _set_bit(2); + type_ = value; +} + +// required bool expect_response = 4; +inline bool Message::has_expect_response() const { + return _has_bit(3); +} +inline void Message::clear_expect_response() { + expect_response_ = false; + _clear_bit(3); +} +inline bool Message::expect_response() const { + return expect_response_; +} +inline void Message::set_expect_response(bool value) { + _set_bit(3); + expect_response_ = value; +} + +// optional int32 ret = 5; +inline bool Message::has_ret() const { + return _has_bit(4); +} +inline void Message::clear_ret() { + ret_ = 0; + _clear_bit(4); +} +inline ::google::protobuf::int32 Message::ret() const { + return ret_; +} +inline void Message::set_ret(::google::protobuf::int32 value) { + _set_bit(4); + ret_ = value; +} + +// optional int32 arg0 = 6; +inline bool Message::has_arg0() const { + return _has_bit(5); +} +inline void Message::clear_arg0() { + arg0_ = 0; + _clear_bit(5); +} +inline ::google::protobuf::int32 Message::arg0() const { + return arg0_; +} +inline void Message::set_arg0(::google::protobuf::int32 value) { + _set_bit(5); + arg0_ = value; +} + +// optional int32 arg1 = 7; +inline bool Message::has_arg1() const { + return _has_bit(6); +} +inline void Message::clear_arg1() { + arg1_ = 0; + _clear_bit(6); +} +inline ::google::protobuf::int32 Message::arg1() const { + return arg1_; +} +inline void Message::set_arg1(::google::protobuf::int32 value) { + _set_bit(6); + arg1_ = value; +} + +// optional int32 arg2 = 8; +inline bool Message::has_arg2() const { + return _has_bit(7); +} +inline void Message::clear_arg2() { + arg2_ = 0; + _clear_bit(7); +} +inline ::google::protobuf::int32 Message::arg2() const { + return arg2_; +} +inline void Message::set_arg2(::google::protobuf::int32 value) { + _set_bit(7); + arg2_ = value; +} + +// optional int32 arg3 = 9; +inline bool Message::has_arg3() const { + return _has_bit(8); +} +inline void Message::clear_arg3() { + arg3_ = 0; + _clear_bit(8); +} +inline ::google::protobuf::int32 Message::arg3() const { + return arg3_; +} +inline void Message::set_arg3(::google::protobuf::int32 value) { + _set_bit(8); + arg3_ = value; +} + +// optional int32 arg4 = 16; +inline bool Message::has_arg4() const { + return _has_bit(9); +} +inline void Message::clear_arg4() { + arg4_ = 0; + _clear_bit(9); +} +inline ::google::protobuf::int32 Message::arg4() const { + return arg4_; +} +inline void Message::set_arg4(::google::protobuf::int32 value) { + _set_bit(9); + arg4_ = value; +} + +// optional int32 arg5 = 17; +inline bool Message::has_arg5() const { + return _has_bit(10); +} +inline void Message::clear_arg5() { + arg5_ = 0; + _clear_bit(10); +} +inline ::google::protobuf::int32 Message::arg5() const { + return arg5_; +} +inline void Message::set_arg5(::google::protobuf::int32 value) { + _set_bit(10); + arg5_ = value; +} + +// optional int32 arg6 = 18; +inline bool Message::has_arg6() const { + return _has_bit(11); +} +inline void Message::clear_arg6() { + arg6_ = 0; + _clear_bit(11); +} +inline ::google::protobuf::int32 Message::arg6() const { + return arg6_; +} +inline void Message::set_arg6(::google::protobuf::int32 value) { + _set_bit(11); + arg6_ = value; +} + +// optional int32 arg7 = 19; +inline bool Message::has_arg7() const { + return _has_bit(12); +} +inline void Message::clear_arg7() { + arg7_ = 0; + _clear_bit(12); +} +inline ::google::protobuf::int32 Message::arg7() const { + return arg7_; +} +inline void Message::set_arg7(::google::protobuf::int32 value) { + _set_bit(12); + arg7_ = value; +} + +// optional int32 arg8 = 20; +inline bool Message::has_arg8() const { + return _has_bit(13); +} +inline void Message::clear_arg8() { + arg8_ = 0; + _clear_bit(13); +} +inline ::google::protobuf::int32 Message::arg8() const { + return arg8_; +} +inline void Message::set_arg8(::google::protobuf::int32 value) { + _set_bit(13); + arg8_ = value; +} + +// optional bytes data = 10; +inline bool Message::has_data() const { + return _has_bit(14); +} +inline void Message::clear_data() { + if (data_ != &_default_data_) { + data_->clear(); + } + _clear_bit(14); +} +inline const ::std::string& Message::data() const { + return *data_; +} +inline void Message::set_data(const ::std::string& value) { + _set_bit(14); + if (data_ == &_default_data_) { + data_ = new ::std::string; + } + data_->assign(value); +} +inline void Message::set_data(const char* value) { + _set_bit(14); + if (data_ == &_default_data_) { + data_ = new ::std::string; + } + data_->assign(value); +} +inline void Message::set_data(const void* value, size_t size) { + _set_bit(14); + if (data_ == &_default_data_) { + data_ = new ::std::string; + } + data_->assign(reinterpret_cast<const char*>(value), size); +} +inline ::std::string* Message::mutable_data() { + _set_bit(14); + if (data_ == &_default_data_) { + data_ = new ::std::string; + } + return data_; +} + +// optional .com.android.glesv2debugger.Message.DataType data_type = 23; +inline bool Message::has_data_type() const { + return _has_bit(15); +} +inline void Message::clear_data_type() { + data_type_ = 0; + _clear_bit(15); +} +inline ::com::android::glesv2debugger::Message_DataType Message::data_type() const { + return static_cast< ::com::android::glesv2debugger::Message_DataType >(data_type_); +} +inline void Message::set_data_type(::com::android::glesv2debugger::Message_DataType value) { + GOOGLE_DCHECK(::com::android::glesv2debugger::Message_DataType_IsValid(value)); + _set_bit(15); + data_type_ = value; +} + +// optional int32 pixel_format = 24; +inline bool Message::has_pixel_format() const { + return _has_bit(16); +} +inline void Message::clear_pixel_format() { + pixel_format_ = 0; + _clear_bit(16); +} +inline ::google::protobuf::int32 Message::pixel_format() const { + return pixel_format_; +} +inline void Message::set_pixel_format(::google::protobuf::int32 value) { + _set_bit(16); + pixel_format_ = value; +} + +// optional int32 pixel_type = 25; +inline bool Message::has_pixel_type() const { + return _has_bit(17); +} +inline void Message::clear_pixel_type() { + pixel_type_ = 0; + _clear_bit(17); +} +inline ::google::protobuf::int32 Message::pixel_type() const { + return pixel_type_; +} +inline void Message::set_pixel_type(::google::protobuf::int32 value) { + _set_bit(17); + pixel_type_ = value; +} + +// optional float time = 11; +inline bool Message::has_time() const { + return _has_bit(18); +} +inline void Message::clear_time() { + time_ = 0; + _clear_bit(18); +} +inline float Message::time() const { + return time_; +} +inline void Message::set_time(float value) { + _set_bit(18); + time_ = value; +} + +// optional .com.android.glesv2debugger.Message.Prop prop = 21; +inline bool Message::has_prop() const { + return _has_bit(19); +} +inline void Message::clear_prop() { + prop_ = 0; + _clear_bit(19); +} +inline ::com::android::glesv2debugger::Message_Prop Message::prop() const { + return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_); +} +inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) { + GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value)); + _set_bit(19); + prop_ = value; +} + +// optional float clock = 22; +inline bool Message::has_clock() const { + return _has_bit(20); +} +inline void Message::clear_clock() { + clock_ = 0; + _clear_bit(20); +} +inline float Message::clock() const { + return clock_; +} +inline void Message::set_clock(float value) { + _set_bit(20); + clock_ = value; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace glesv2debugger +} // namespace android +} // namespace com + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_debugger_5fmessage_2eproto__INCLUDED diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp new file mode 100644 index 0000000..3a20e21 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/egl.cpp @@ -0,0 +1,39 @@ +/* + ** 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. + */ + +#include "header.h" + +EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) +{ + glesv2debugger::Message msg; + struct : public FunctionCall { + EGLDisplay dpy; + EGLSurface draw; + + const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) { + msg.set_time(-1); + return reinterpret_cast<const int *>(true); + } + } caller; + caller.dpy = dpy; + caller.draw = draw; + + msg.set_arg0(reinterpret_cast<int>(dpy)); + msg.set_arg1(reinterpret_cast<int>(draw)); + + int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_eglSwapBuffers); + return static_cast<EGLBoolean>(reinterpret_cast<int>(ret)); +} diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h new file mode 100644 index 0000000..7e9aa4e --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/header.h @@ -0,0 +1,172 @@ +/* + ** 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. + */ + +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <cutils/log.h> +#include <utils/Timers.h> +#include <../../../libcore/include/StaticAssert.h> + +#define EGL_TRACE 1 +#include "hooks.h" + +#include "glesv2dbg.h" + +#define GL_ENTRY(_r, _api, ...) _r Debug_##_api ( __VA_ARGS__ ); +#include "glesv2dbg_functions.h" + +#include "debugger_message.pb.h" + +using namespace android; +using namespace com::android; + +#define API_ENTRY(_api) Debug_##_api + +#ifndef __location__ +#define __HIERALLOC_STRING_0__(s) #s +#define __HIERALLOC_STRING_1__(s) __HIERALLOC_STRING_0__(s) +#define __HIERALLOC_STRING_2__ __HIERALLOC_STRING_1__(__LINE__) +#define __location__ __FILE__ ":" __HIERALLOC_STRING_2__ +#endif + +#undef assert +#define assert(expr) if (!(expr)) { LOGD("\n*\n*\n* assert: %s at %s \n*\n*", #expr, __location__); int * x = 0; *x = 5; } +//#undef LOGD +//#define LOGD(...) + +namespace android +{ + +struct GLFunctionBitfield +{ + unsigned char field [24]; // 8 * 24 = 192 + + void Bit(const glesv2debugger::Message_Function function, bool bit) + { + const unsigned byte = function / 8, mask = 1 << (function % 8); + if (bit) + field[byte] |= mask; + else + field[byte] &= ~mask; + } + + bool Bit(const glesv2debugger::Message_Function function) const + { + const unsigned byte = function / 8, mask = 1 << (function % 8); + return field[byte] & mask; + } +}; + +struct DbgContext { +private: + unsigned lzf_bufSize; + + // used as buffer and reference frame for ReadPixels; malloc/free + unsigned * lzf_ref [2]; + unsigned lzf_readIndex; // 0 or 1 + unsigned lzf_refSize, lzf_refBufSize; // bytes + +public: + char * lzf_buf; // auto malloc/free; output of lzf_compress + + const unsigned version; // 0 is GLES1, 1 is GLES2 + const gl_hooks_t * const hooks; + const unsigned MAX_VERTEX_ATTRIBS; + + GLFunctionBitfield expectResponse; + + struct VertexAttrib { + GLenum type; // element data type + unsigned size; // number of data per element + unsigned stride; // calculated number of bytes between elements + const void * ptr; + unsigned elemSize; // calculated number of bytes per element + GLuint buffer; // buffer name + GLboolean normalized : 1; + GLboolean enabled : 1; + VertexAttrib() : type(0), size(0), stride(0), ptr(NULL), elemSize(0), + buffer(0), normalized(0), enabled(0) {} + } * vertexAttribs; + bool hasNonVBOAttribs; // whether any enabled vertexAttrib is user pointer + + struct VBO { + const GLuint name; + const GLenum target; + VBO * next; + void * data; // malloc/free + unsigned size; // in bytes + VBO(const GLuint name, const GLenum target, VBO * head) : name(name), + target(target), next(head), data(NULL), size(0) {} + } * indexBuffers; // linked list of all index buffers + VBO * indexBuffer; // currently bound index buffer + + GLuint program; + unsigned maxAttrib; // number of slots used by program + + DbgContext(const unsigned version, const gl_hooks_t * const hooks, const unsigned MAX_VERTEX_ATTRIBS); + ~DbgContext(); + + void Fetch(const unsigned index, std::string * const data) const; + unsigned Compress(const void * in_data, unsigned in_len); // compressed to lzf_buf + void * GetReadPixelsBuffer(const unsigned size); + bool IsReadPixelBuffer(const void * const ptr) { + return ptr == lzf_ref[lzf_readIndex]; + } + unsigned CompressReadPixelBuffer(); + + void glUseProgram(GLuint program); + void glEnableVertexAttribArray(GLuint index); + void glDisableVertexAttribArray(GLuint index); + void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr); + void glBindBuffer(GLenum target, GLuint buffer); + void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); + void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); + void glDeleteBuffers(GLsizei n, const GLuint *buffers); +}; + + +DbgContext * getDbgContextThreadSpecific(); +#define DBGCONTEXT(ctx) DbgContext * const ctx = getDbgContextThreadSpecific(); + +struct FunctionCall { + virtual const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) = 0; + virtual ~FunctionCall() {} +}; + +// move these into DbgContext as static +extern bool capture; +extern int timeMode; // SYSTEM_TIME_ + +extern int clientSock, serverSock; + +unsigned GetBytesPerPixel(const GLenum format, const GLenum type); + +// every Debug_gl* function calls this to send message to client and possibly receive commands +int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg, + const glesv2debugger::Message_Function function); + +void Receive(glesv2debugger::Message & cmd); +float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd); +void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd); +const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd, + glesv2debugger::Message & msg, const int * const prevRet); +}; // namespace android { diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp new file mode 100644 index 0000000..7039c84 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/server.cpp @@ -0,0 +1,257 @@ +/* + ** 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. + */ + +#include <sys/ioctl.h> +#include <unistd.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <pthread.h> + +#include "header.h" + +namespace android +{ + +int serverSock = -1, clientSock = -1; + +int timeMode = SYSTEM_TIME_THREAD; + +static void Die(const char * msg) +{ + LOGD("\n*\n*\n* GLESv2_dbg: Die: %s \n*\n*", msg); + StopDebugServer(); + exit(1); +} + +void StartDebugServer(unsigned short port) +{ + LOGD("GLESv2_dbg: StartDebugServer"); + if (serverSock >= 0) + return; + + LOGD("GLESv2_dbg: StartDebugServer create socket"); + struct sockaddr_in server = {}, client = {}; + + /* Create the TCP socket */ + if ((serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + Die("Failed to create socket"); + } + /* Construct the server sockaddr_in structure */ + server.sin_family = AF_INET; /* Internet/IP */ + server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* Incoming addr */ + server.sin_port = htons(port); /* server port */ + + /* Bind the server socket */ + socklen_t sizeofSockaddr_in = sizeof(sockaddr_in); + if (bind(serverSock, (struct sockaddr *) &server, + sizeof(server)) < 0) { + Die("Failed to bind the server socket"); + } + /* Listen on the server socket */ + if (listen(serverSock, 1) < 0) { + Die("Failed to listen on server socket"); + } + + LOGD("server started on %d \n", server.sin_port); + + + /* Wait for client connection */ + if ((clientSock = + accept(serverSock, (struct sockaddr *) &client, + &sizeofSockaddr_in)) < 0) { + Die("Failed to accept client connection"); + } + + LOGD("Client connected: %s\n", inet_ntoa(client.sin_addr)); +// fcntl(clientSock, F_SETFL, O_NONBLOCK); +} + +void StopDebugServer() +{ + LOGD("GLESv2_dbg: StopDebugServer"); + if (clientSock > 0) { + close(clientSock); + clientSock = -1; + } + if (serverSock > 0) { + close(serverSock); + serverSock = -1; + } + +} + +void Receive(glesv2debugger::Message & cmd) +{ + unsigned len = 0; + + int received = recv(clientSock, &len, 4, MSG_WAITALL); + if (received < 0) + Die("Failed to receive response length"); + else if (4 != received) { + LOGD("received %dB: %.8X", received, len); + Die("Received length mismatch, expected 4"); + } + len = ntohl(len); + static void * buffer = NULL; + static unsigned bufferSize = 0; + if (bufferSize < len) { + buffer = realloc(buffer, len); + assert(buffer); + bufferSize = len; + } + received = recv(clientSock, buffer, len, MSG_WAITALL); + if (received < 0) + Die("Failed to receive response"); + else if (len != received) + Die("Received length mismatch"); + cmd.Clear(); + cmd.ParseFromArray(buffer, len); +} + +bool TryReceive(glesv2debugger::Message & cmd) +{ + fd_set readSet; + FD_ZERO(&readSet); + FD_SET(clientSock, &readSet); + timeval timeout; + timeout.tv_sec = timeout.tv_usec = 0; + + int rc = select(clientSock + 1, &readSet, NULL, NULL, &timeout); + if (rc < 0) + Die("failed to select clientSock"); + + bool received = false; + if (FD_ISSET(clientSock, &readSet)) { + LOGD("TryReceive: avaiable for read"); + Receive(cmd); + return true; + } + return false; +} + +float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd) +{ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&mutex); // TODO: this is just temporary + + if (msg.function() != glesv2debugger::Message_Function_ACK) + assert(msg.has_context_id() && msg.context_id() != 0); + static std::string str; + msg.SerializeToString(&str); + uint32_t len = htonl(str.length()); + int sent = -1; + sent = send(clientSock, &len, sizeof(len), 0); + if (sent != sizeof(len)) { + LOGD("actual sent=%d expected=%d clientSock=%d", sent, sizeof(len), clientSock); + Die("Failed to send message length"); + } + nsecs_t c0 = systemTime(timeMode); + sent = send(clientSock, str.c_str(), str.length(), 0); + float t = (float)ns2ms(systemTime(timeMode) - c0); + if (sent != str.length()) { + LOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock); + Die("Failed to send message"); + } + + // try to receive commands even though not expecting response, + // since client can send SETPROP commands anytime + if (!msg.expect_response()) { + if (TryReceive(cmd)) { + LOGD("Send: TryReceived"); + if (glesv2debugger::Message_Function_SETPROP == cmd.function()) + LOGD("Send: received SETPROP"); + else + LOGD("Send: received something else"); + } + } else + Receive(cmd); + + pthread_mutex_unlock(&mutex); + return t; +} + +void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd) +{ + switch (cmd.prop()) { + case glesv2debugger::Message_Prop_Capture: + LOGD("SetProp Message_Prop_Capture %d", cmd.arg0()); + capture = cmd.arg0(); + break; + case glesv2debugger::Message_Prop_TimeMode: + LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0()); + timeMode = cmd.arg0(); + break; + case glesv2debugger::Message_Prop_ExpectResponse: + LOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1()); + dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1()); + break; + default: + assert(0); + } +} + +int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg, + const glesv2debugger::Message_Function function) +{ + DbgContext * const dbg = getDbgContextThreadSpecific(); + const int * ret = 0; + glesv2debugger::Message cmd; + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_type(glesv2debugger::Message_Type_BeforeCall); + const bool expectResponse = dbg->expectResponse.Bit(function); + msg.set_expect_response(expectResponse); + msg.set_function(function); + if (!expectResponse) + cmd.set_function(glesv2debugger::Message_Function_CONTINUE); + Send(msg, cmd); + while (true) { + msg.Clear(); + nsecs_t c0 = systemTime(timeMode); + switch (cmd.function()) { + case glesv2debugger::Message_Function_CONTINUE: + ret = functionCall(&dbg->hooks->gl, msg); + while (GLenum error = dbg->hooks->gl.glGetError()) + LOGD("Function=%u glGetError() = 0x%.4X", function, error); + if (!msg.has_time()) // some has output data copy, so time inside call + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_function(function); + msg.set_type(glesv2debugger::Message_Type_AfterCall); + msg.set_expect_response(expectResponse); + if (!expectResponse) + cmd.set_function(glesv2debugger::Message_Function_SKIP); + Send(msg, cmd); + break; + case glesv2debugger::Message_Function_SKIP: + return const_cast<int *>(ret); + case glesv2debugger::Message_Function_SETPROP: + SetProp(dbg, cmd); + Receive(cmd); + break; + default: + ret = GenerateCall(dbg, cmd, msg, ret); + msg.set_expect_response(expectResponse); + if (!expectResponse) + cmd.set_function(cmd.SKIP); + Send(msg, cmd); + break; + } + } + return 0; +} +}; // namespace android { diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp new file mode 100644 index 0000000..a9cf9e7 --- /dev/null +++ b/opengl/libs/GLES2_dbg/src/vertex.cpp @@ -0,0 +1,246 @@ +/* + ** 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. + */ + +#include "header.h" + +namespace android +{ +bool capture; // capture after each glDraw* +} + +void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) +{ + DbgContext * const dbg = getDbgContextThreadSpecific(); + glesv2debugger::Message msg, cmd; + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_type(glesv2debugger::Message_Type_BeforeCall); + const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glReadPixels); + msg.set_expect_response(expectResponse); + msg.set_function(glesv2debugger::Message_Function_glReadPixels); + msg.set_arg0(x); + msg.set_arg1(y); + msg.set_arg2(width); + msg.set_arg3(height); + msg.set_arg4(format); + msg.set_arg5(type); + msg.set_arg6(reinterpret_cast<int>(pixels)); + + const unsigned size = width * height * GetBytesPerPixel(format, type); + unsigned compressed = 0; + if (!expectResponse) + cmd.set_function(glesv2debugger::Message_Function_CONTINUE); + Send(msg, cmd); + float t = 0; + while (true) { + msg.Clear(); + nsecs_t c0 = systemTime(timeMode); + switch (cmd.function()) { + case glesv2debugger::Message_Function_CONTINUE: + dbg->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_function(glesv2debugger::Message_Function_glReadPixels); + msg.set_type(glesv2debugger::Message_Type_AfterCall); + msg.set_expect_response(expectResponse); + if (dbg->IsReadPixelBuffer(pixels)) { + compressed = dbg->CompressReadPixelBuffer(); + msg.set_data_type(msg.ReferencedImage); + } else { + compressed = dbg->Compress(pixels, size); + msg.set_data_type(msg.NonreferencedImage); + } + msg.set_data(dbg->lzf_buf, compressed); + if (!expectResponse) + cmd.set_function(glesv2debugger::Message_Function_SKIP); + Send(msg, cmd); + break; + case glesv2debugger::Message_Function_SKIP: + return; + case glesv2debugger::Message_Function_SETPROP: + SetProp(dbg, cmd); + Receive(cmd); + break; + default: + GenerateCall(dbg, cmd, msg, NULL); + msg.set_expect_response(expectResponse); + if (!expectResponse) + cmd.set_function(cmd.SKIP); + Send(msg, cmd); + break; + } + } +} + +void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + DbgContext * const dbg = getDbgContextThreadSpecific(); + glesv2debugger::Message msg, cmd; + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_type(glesv2debugger::Message_Type_BeforeCall); + const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays); + msg.set_expect_response(expectResponse); + msg.set_function(glesv2debugger::Message_Function_glDrawArrays); + msg.set_arg0(mode); + msg.set_arg1(first); + msg.set_arg2(count); + + msg.set_arg7(dbg->maxAttrib); // indicate capturing vertex data + if (dbg->hasNonVBOAttribs) { + std::string * const data = msg.mutable_data(); + for (unsigned i = 0; i < count; i++) + dbg->Fetch(i + first, data); + } + + void * pixels = NULL; + GLint readFormat = 0, readType = 0; + int viewport[4] = {}; + if (!expectResponse) + cmd.set_function(glesv2debugger::Message_Function_CONTINUE); + Send(msg, cmd); + while (true) { + msg.Clear(); + nsecs_t c0 = systemTime(timeMode); + switch (cmd.function()) { + case glesv2debugger::Message_Function_CONTINUE: + dbg->hooks->gl.glDrawArrays(mode, first, count); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_function(glesv2debugger::Message_Function_glDrawArrays); + msg.set_type(glesv2debugger::Message_Type_AfterCall); + msg.set_expect_response(expectResponse); + if (!expectResponse) + cmd.set_function(glesv2debugger::Message_Function_SKIP); + Send(msg, cmd); + if (capture) { + dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport); + dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); + dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); +// LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X", +// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType); + pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] * + GetBytesPerPixel(readFormat, readType)); + Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], + readFormat, readType, pixels); + } + break; + case glesv2debugger::Message_Function_SKIP: + return; + case glesv2debugger::Message_Function_SETPROP: + SetProp(dbg, cmd); + Receive(cmd); + break; + default: + GenerateCall(dbg, cmd, msg, NULL); + msg.set_expect_response(expectResponse); + if (!expectResponse) + cmd.set_function(cmd.SKIP); + Send(msg, cmd); + break; + } + } +} + +template<typename T> +static inline void FetchIndexed(const unsigned count, const T * indices, + std::string * const data, const DbgContext * const ctx) +{ + for (unsigned i = 0; i < count; i++) { + if (!ctx->indexBuffer) + data->append((const char *)(indices + i), sizeof(*indices)); + if (ctx->hasNonVBOAttribs) + ctx->Fetch(indices[i], data); + } +} + +void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +{ + DbgContext * const dbg = getDbgContextThreadSpecific(); + glesv2debugger::Message msg, cmd; + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_type(glesv2debugger::Message_Type_BeforeCall); + const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements); + msg.set_expect_response(expectResponse); + msg.set_function(glesv2debugger::Message_Function_glDrawElements); + msg.set_arg0(mode); + msg.set_arg1(count); + msg.set_arg2(type); + msg.set_arg3(reinterpret_cast<int>(indices)); + + msg.set_arg7(dbg->maxAttrib); // indicate capturing vertex data + std::string * const data = msg.mutable_data(); + if (GL_UNSIGNED_BYTE == type) { + if (dbg->indexBuffer) + FetchIndexed(count, (unsigned char *)dbg->indexBuffer->data + + (unsigned long)indices, data, dbg); + else + FetchIndexed(count, (unsigned char *)indices, data, dbg); + } else if (GL_UNSIGNED_SHORT == type) { + if (dbg->indexBuffer) + FetchIndexed(count, (unsigned short *)((char *)dbg->indexBuffer->data + + (unsigned long)indices), data, dbg); + else + FetchIndexed(count, (unsigned short *)indices, data, dbg); + } else + assert(0); + + void * pixels = NULL; + GLint readFormat = 0, readType = 0; + int viewport[4] = {}; + if (!expectResponse) + cmd.set_function(glesv2debugger::Message_Function_CONTINUE); + Send(msg, cmd); + while (true) { + msg.Clear(); + nsecs_t c0 = systemTime(timeMode); + switch (cmd.function()) { + case glesv2debugger::Message_Function_CONTINUE: + dbg->hooks->gl.glDrawElements(mode, count, type, indices); + msg.set_time((systemTime(timeMode) - c0) * 1e-6f); + msg.set_context_id(reinterpret_cast<int>(dbg)); + msg.set_function(glesv2debugger::Message_Function_glDrawElements); + msg.set_type(glesv2debugger::Message_Type_AfterCall); + msg.set_expect_response(expectResponse); + if (!expectResponse) + cmd.set_function(glesv2debugger::Message_Function_SKIP); + Send(msg, cmd); + if (capture) { + dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport); + dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); + dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); +// LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X", +// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType); + pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] * + GetBytesPerPixel(readFormat, readType)); + Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], + readFormat, readType, pixels); + } + break; + case glesv2debugger::Message_Function_SKIP: + return; + case glesv2debugger::Message_Function_SETPROP: + SetProp(dbg, cmd); + Receive(cmd); + break; + default: + GenerateCall(dbg, cmd, msg, NULL); + msg.set_expect_response(expectResponse); + if (!expectResponse) + cmd.set_function(cmd.SKIP); + Send(msg, cmd); + break; + } + } +} diff --git a/opengl/libs/debug.in b/opengl/libs/debug.in new file mode 100644 index 0000000..882b2da --- /dev/null +++ b/opengl/libs/debug.in @@ -0,0 +1,235 @@ +// the following functions are not defined in GLESv2_dbg +TRACE_GL_VOID(glAlphaFunc, (GLenum func, GLclampf ref), (func, ref), 2, "GLenum", func, "GLclampf", ref) +TRACE_GL_VOID(glAlphaFuncx, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref) +TRACE_GL_VOID(glAlphaFuncxOES, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref) +TRACE_GL_VOID(glBeginPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor) +TRACE_GL_VOID(glBindFramebufferOES, (GLenum target, GLuint framebuffer), (target, framebuffer), 2, "GLenum", target, "GLuint", framebuffer) +TRACE_GL_VOID(glBindRenderbufferOES, (GLenum target, GLuint renderbuffer), (target, renderbuffer), 2, "GLenum", target, "GLuint", renderbuffer) +TRACE_GL_VOID(glBindVertexArrayOES, (GLuint array), (array), 1, "GLuint", array) +TRACE_GL_VOID(glBlendEquationOES, (GLenum mode), (mode), 1, "GLenum", mode) +TRACE_GL_VOID(glBlendEquationSeparateOES, (GLenum modeRGB, GLenum modeAlpha), (modeRGB, modeAlpha), 2, "GLenum", modeRGB, "GLenum", modeAlpha) +TRACE_GL_VOID(glBlendFuncSeparateOES, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), (srcRGB, dstRGB, srcAlpha, dstAlpha), 4, "GLenum", srcRGB, "GLenum", dstRGB, "GLenum", srcAlpha, "GLenum", dstAlpha) +TRACE_GL(GLenum, glCheckFramebufferStatusOES, (GLenum target), (target), 1, "GLenum", target) +TRACE_GL_VOID(glClearColorx, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha), (red, green, blue, alpha), 4, "GLclampx", red, "GLclampx", green, "GLclampx", blue, "GLclampx", alpha) +TRACE_GL_VOID(glClearColorxOES, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha), (red, green, blue, alpha), 4, "GLclampx", red, "GLclampx", green, "GLclampx", blue, "GLclampx", alpha) +TRACE_GL_VOID(glClearDepthfOES, (GLclampf depth), (depth), 1, "GLclampf", depth) +TRACE_GL_VOID(glClearDepthx, (GLclampx depth), (depth), 1, "GLclampx", depth) +TRACE_GL_VOID(glClearDepthxOES, (GLclampx depth), (depth), 1, "GLclampx", depth) +TRACE_GL_VOID(glClientActiveTexture, (GLenum texture), (texture), 1, "GLenum", texture) +TRACE_GL_VOID(glClipPlanef, (GLenum plane, const GLfloat *equation), (plane, equation), 2, "GLenum", plane, "const GLfloat *", equation) +TRACE_GL_VOID(glClipPlanefIMG, (GLenum p, const GLfloat *eqn), (p, eqn), 2, "GLenum", p, "const GLfloat *", eqn) +TRACE_GL_VOID(glClipPlanefOES, (GLenum plane, const GLfloat *equation), (plane, equation), 2, "GLenum", plane, "const GLfloat *", equation) +TRACE_GL_VOID(glClipPlanex, (GLenum plane, const GLfixed *equation), (plane, equation), 2, "GLenum", plane, "const GLfixed *", equation) +TRACE_GL_VOID(glClipPlanexIMG, (GLenum p, const GLfixed *eqn), (p, eqn), 2, "GLenum", p, "const GLfixed *", eqn) +TRACE_GL_VOID(glClipPlanexOES, (GLenum plane, const GLfixed *equation), (plane, equation), 2, "GLenum", plane, "const GLfixed *", equation) +TRACE_GL_VOID(glColor4f, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha), (red, green, blue, alpha), 4, "GLfloat", red, "GLfloat", green, "GLfloat", blue, "GLfloat", alpha) +TRACE_GL_VOID(glColor4ub, (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha), (red, green, blue, alpha), 4, "GLubyte", red, "GLubyte", green, "GLubyte", blue, "GLubyte", alpha) +TRACE_GL_VOID(glColor4x, (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha), (red, green, blue, alpha), 4, "GLfixed", red, "GLfixed", green, "GLfixed", blue, "GLfixed", alpha) +TRACE_GL_VOID(glColor4xOES, (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha), (red, green, blue, alpha), 4, "GLfixed", red, "GLfixed", green, "GLfixed", blue, "GLfixed", alpha) +TRACE_GL_VOID(glColorPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer) +TRACE_GL_VOID(glCompressedTexImage3DOES, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data), (target, level, internalformat, width, height, depth, border, imageSize, data), 9, "GLenum", target, "GLint", level, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLint", border, "GLsizei", imageSize, "const GLvoid*", data) +TRACE_GL_VOID(glCompressedTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLsizei", imageSize, "const GLvoid*", data) +TRACE_GL_VOID(glCopyTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height), (target, level, xoffset, yoffset, zoffset, x, y, width, height), 9, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height) +TRACE_GL_VOID(glCoverageMaskNV, (GLboolean mask), (mask), 1, "GLboolean", mask) +TRACE_GL_VOID(glCoverageOperationNV, (GLenum operation), (operation), 1, "GLenum", operation) +TRACE_GL_VOID(glCurrentPaletteMatrixOES, (GLuint matrixpaletteindex), (matrixpaletteindex), 1, "GLuint", matrixpaletteindex) +TRACE_GL_VOID(glDeleteFencesNV, (GLsizei n, const GLuint *fences), (n, fences), 2, "GLsizei", n, "const GLuint *", fences) +TRACE_GL_VOID(glDeleteFramebuffersOES, (GLsizei n, const GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "const GLuint*", framebuffers) +TRACE_GL_VOID(glDeletePerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors) +TRACE_GL_VOID(glDeleteRenderbuffersOES, (GLsizei n, const GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "const GLuint*", renderbuffers) +TRACE_GL_VOID(glDeleteVertexArraysOES, (GLsizei n, const GLuint *arrays), (n, arrays), 2, "GLsizei", n, "const GLuint *", arrays) +TRACE_GL_VOID(glDepthRangefOES, (GLclampf zNear, GLclampf zFar), (zNear, zFar), 2, "GLclampf", zNear, "GLclampf", zFar) +TRACE_GL_VOID(glDepthRangex, (GLclampx zNear, GLclampx zFar), (zNear, zFar), 2, "GLclampx", zNear, "GLclampx", zFar) +TRACE_GL_VOID(glDepthRangexOES, (GLclampx zNear, GLclampx zFar), (zNear, zFar), 2, "GLclampx", zNear, "GLclampx", zFar) +TRACE_GL_VOID(glDisableClientState, (GLenum array), (array), 1, "GLenum", array) +TRACE_GL_VOID(glDisableDriverControlQCOM, (GLuint driverControl), (driverControl), 1, "GLuint", driverControl) +TRACE_GL_VOID(glDiscardFramebufferEXT, (GLenum target, GLsizei numAttachments, const GLenum *attachments), (target, numAttachments, attachments), 3, "GLenum", target, "GLsizei", numAttachments, "const GLenum *", attachments) +TRACE_GL_VOID(glDrawTexfOES, (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height), (x, y, z, width, height), 5, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", width, "GLfloat", height) +TRACE_GL_VOID(glDrawTexfvOES, (const GLfloat *coords), (coords), 1, "const GLfloat *", coords) +TRACE_GL_VOID(glDrawTexiOES, (GLint x, GLint y, GLint z, GLint width, GLint height), (x, y, z, width, height), 5, "GLint", x, "GLint", y, "GLint", z, "GLint", width, "GLint", height) +TRACE_GL_VOID(glDrawTexivOES, (const GLint *coords), (coords), 1, "const GLint *", coords) +TRACE_GL_VOID(glDrawTexsOES, (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height), (x, y, z, width, height), 5, "GLshort", x, "GLshort", y, "GLshort", z, "GLshort", width, "GLshort", height) +TRACE_GL_VOID(glDrawTexsvOES, (const GLshort *coords), (coords), 1, "const GLshort *", coords) +TRACE_GL_VOID(glDrawTexxOES, (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height), (x, y, z, width, height), 5, "GLfixed", x, "GLfixed", y, "GLfixed", z, "GLfixed", width, "GLfixed", height) +TRACE_GL_VOID(glDrawTexxvOES, (const GLfixed *coords), (coords), 1, "const GLfixed *", coords) +TRACE_GL_VOID(glEGLImageTargetRenderbufferStorageOES, (GLenum target, GLeglImageOES image), (target, image), 2, "GLenum", target, "GLeglImageOES", image) +TRACE_GL_VOID(glEGLImageTargetTexture2DOES, (GLenum target, GLeglImageOES image), (target, image), 2, "GLenum", target, "GLeglImageOES", image) +TRACE_GL_VOID(glEnableClientState, (GLenum array), (array), 1, "GLenum", array) +TRACE_GL_VOID(glEnableDriverControlQCOM, (GLuint driverControl), (driverControl), 1, "GLuint", driverControl) +TRACE_GL_VOID(glEndPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor) +TRACE_GL_VOID(glEndTilingQCOM, (GLbitfield preserveMask), (preserveMask), 1, "GLbitfield", preserveMask) +TRACE_GL_VOID(glExtGetBufferPointervQCOM, (GLenum target, GLvoid **params), (target, params), 2, "GLenum", target, "GLvoid **", params) +TRACE_GL_VOID(glExtGetBuffersQCOM, (GLuint *buffers, GLint maxBuffers, GLint *numBuffers), (buffers, maxBuffers, numBuffers), 3, "GLuint *", buffers, "GLint", maxBuffers, "GLint *", numBuffers) +TRACE_GL_VOID(glExtGetFramebuffersQCOM, (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers), (framebuffers, maxFramebuffers, numFramebuffers), 3, "GLuint *", framebuffers, "GLint", maxFramebuffers, "GLint *", numFramebuffers) +TRACE_GL_VOID(glExtGetProgramBinarySourceQCOM, (GLuint program, GLenum shadertype, GLchar *source, GLint *length), (program, shadertype, source, length), 4, "GLuint", program, "GLenum", shadertype, "GLchar *", source, "GLint *", length) +TRACE_GL_VOID(glExtGetProgramsQCOM, (GLuint *programs, GLint maxPrograms, GLint *numPrograms), (programs, maxPrograms, numPrograms), 3, "GLuint *", programs, "GLint", maxPrograms, "GLint *", numPrograms) +TRACE_GL_VOID(glExtGetRenderbuffersQCOM, (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers), (renderbuffers, maxRenderbuffers, numRenderbuffers), 3, "GLuint *", renderbuffers, "GLint", maxRenderbuffers, "GLint *", numRenderbuffers) +TRACE_GL_VOID(glExtGetShadersQCOM, (GLuint *shaders, GLint maxShaders, GLint *numShaders), (shaders, maxShaders, numShaders), 3, "GLuint *", shaders, "GLint", maxShaders, "GLint *", numShaders) +TRACE_GL_VOID(glExtGetTexLevelParameterivQCOM, (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params), (texture, face, level, pname, params), 5, "GLuint", texture, "GLenum", face, "GLint", level, "GLenum", pname, "GLint *", params) +TRACE_GL_VOID(glExtGetTexSubImageQCOM, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLenum", type, "GLvoid *", texels) +TRACE_GL_VOID(glExtGetTexturesQCOM, (GLuint *textures, GLint maxTextures, GLint *numTextures), (textures, maxTextures, numTextures), 3, "GLuint *", textures, "GLint", maxTextures, "GLint *", numTextures) +TRACE_GL(GLboolean, glExtIsProgramBinaryQCOM, (GLuint program), (program), 1, "GLuint", program) +TRACE_GL_VOID(glExtTexObjectStateOverrideiQCOM, (GLenum target, GLenum pname, GLint param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLint", param) +TRACE_GL_VOID(glFinishFenceNV, (GLuint fence), (fence), 1, "GLuint", fence) +TRACE_GL_VOID(glFogf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param) +TRACE_GL_VOID(glFogfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params) +TRACE_GL_VOID(glFogx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glFogxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glFogxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glFogxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glFramebufferRenderbufferOES, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, renderbuffertarget, renderbuffer), 4, "GLenum", target, "GLenum", attachment, "GLenum", renderbuffertarget, "GLuint", renderbuffer) +TRACE_GL_VOID(glFramebufferTexture2DMultisampleIMG, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples), (target, attachment, textarget, texture, level, samples), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLsizei", samples) +TRACE_GL_VOID(glFramebufferTexture2DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level), (target, attachment, textarget, texture, level), 5, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level) +TRACE_GL_VOID(glFramebufferTexture3DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset), (target, attachment, textarget, texture, level, zoffset), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLint", zoffset) +TRACE_GL_VOID(glFrustumf, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar) +TRACE_GL_VOID(glFrustumfOES, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar) +TRACE_GL_VOID(glFrustumx, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar) +TRACE_GL_VOID(glFrustumxOES, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar) +TRACE_GL_VOID(glGenFencesNV, (GLsizei n, GLuint *fences), (n, fences), 2, "GLsizei", n, "GLuint *", fences) +TRACE_GL_VOID(glGenFramebuffersOES, (GLsizei n, GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "GLuint*", framebuffers) +TRACE_GL_VOID(glGenPerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors) +TRACE_GL_VOID(glGenRenderbuffersOES, (GLsizei n, GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "GLuint*", renderbuffers) +TRACE_GL_VOID(glGenVertexArraysOES, (GLsizei n, GLuint *arrays), (n, arrays), 2, "GLsizei", n, "GLuint *", arrays) +TRACE_GL_VOID(glGenerateMipmapOES, (GLenum target), (target), 1, "GLenum", target) +TRACE_GL_VOID(glGetBufferPointervOES, (GLenum target, GLenum pname, GLvoid ** params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLvoid **", params) +TRACE_GL_VOID(glGetClipPlanef, (GLenum pname, GLfloat eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfloat", eqn) +TRACE_GL_VOID(glGetClipPlanefOES, (GLenum pname, GLfloat eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfloat", eqn) +TRACE_GL_VOID(glGetClipPlanex, (GLenum pname, GLfixed eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfixed", eqn) +TRACE_GL_VOID(glGetClipPlanexOES, (GLenum pname, GLfixed eqn[4]), (pname, eqn), 2, "GLenum", pname, "GLfixed", eqn) +TRACE_GL_VOID(glGetDriverControlStringQCOM, (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString), (driverControl, bufSize, length, driverControlString), 4, "GLuint", driverControl, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", driverControlString) +TRACE_GL_VOID(glGetDriverControlsQCOM, (GLint *num, GLsizei size, GLuint *driverControls), (num, size, driverControls), 3, "GLint *", num, "GLsizei", size, "GLuint *", driverControls) +TRACE_GL_VOID(glGetFenceivNV, (GLuint fence, GLenum pname, GLint *params), (fence, pname, params), 3, "GLuint", fence, "GLenum", pname, "GLint *", params) +TRACE_GL_VOID(glGetFixedv, (GLenum pname, GLfixed *params), (pname, params), 2, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetFixedvOES, (GLenum pname, GLfixed *params), (pname, params), 2, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetFramebufferAttachmentParameterivOES, (GLenum target, GLenum attachment, GLenum pname, GLint* params), (target, attachment, pname, params), 4, "GLenum", target, "GLenum", attachment, "GLenum", pname, "GLint*", params) +TRACE_GL_VOID(glGetLightfv, (GLenum light, GLenum pname, GLfloat *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfloat *", params) +TRACE_GL_VOID(glGetLightxv, (GLenum light, GLenum pname, GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetLightxvOES, (GLenum light, GLenum pname, GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetMaterialfv, (GLenum face, GLenum pname, GLfloat *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfloat *", params) +TRACE_GL_VOID(glGetMaterialxv, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetMaterialxvOES, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetPerfMonitorCounterDataAMD, (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten), (monitor, pname, dataSize, data, bytesWritten), 5, "GLuint", monitor, "GLenum", pname, "GLsizei", dataSize, "GLuint *", data, "GLint *", bytesWritten) +TRACE_GL_VOID(glGetPerfMonitorCounterInfoAMD, (GLuint group, GLuint counter, GLenum pname, GLvoid *data), (group, counter, pname, data), 4, "GLuint", group, "GLuint", counter, "GLenum", pname, "GLvoid *", data) +TRACE_GL_VOID(glGetPerfMonitorCounterStringAMD, (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString), (group, counter, bufSize, length, counterString), 5, "GLuint", group, "GLuint", counter, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", counterString) +TRACE_GL_VOID(glGetPerfMonitorCountersAMD, (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters), (group, numCounters, maxActiveCounters, counterSize, counters), 5, "GLuint", group, "GLint *", numCounters, "GLint *", maxActiveCounters, "GLsizei", counterSize, "GLuint *", counters) +TRACE_GL_VOID(glGetPerfMonitorGroupStringAMD, (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString), (group, bufSize, length, groupString), 4, "GLuint", group, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", groupString) +TRACE_GL_VOID(glGetPerfMonitorGroupsAMD, (GLint *numGroups, GLsizei groupsSize, GLuint *groups), (numGroups, groupsSize, groups), 3, "GLint *", numGroups, "GLsizei", groupsSize, "GLuint *", groups) +TRACE_GL_VOID(glGetPointerv, (GLenum pname, GLvoid **params), (pname, params), 2, "GLenum", pname, "GLvoid **", params) +TRACE_GL_VOID(glGetProgramBinaryOES, (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary), (program, bufSize, length, binaryFormat, binary), 5, "GLuint", program, "GLsizei", bufSize, "GLsizei *", length, "GLenum *", binaryFormat, "GLvoid *", binary) +TRACE_GL_VOID(glGetRenderbufferParameterivOES, (GLenum target, GLenum pname, GLint* params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint*", params) +TRACE_GL_VOID(glGetTexEnvfv, (GLenum env, GLenum pname, GLfloat *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfloat *", params) +TRACE_GL_VOID(glGetTexEnviv, (GLenum env, GLenum pname, GLint *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLint *", params) +TRACE_GL_VOID(glGetTexEnvxv, (GLenum env, GLenum pname, GLfixed *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetTexEnvxvOES, (GLenum env, GLenum pname, GLfixed *params), (env, pname, params), 3, "GLenum", env, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetTexGenfvOES, (GLenum coord, GLenum pname, GLfloat *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLfloat *", params) +TRACE_GL_VOID(glGetTexGenivOES, (GLenum coord, GLenum pname, GLint *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLint *", params) +TRACE_GL_VOID(glGetTexGenxvOES, (GLenum coord, GLenum pname, GLfixed *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetTexParameterxv, (GLenum target, GLenum pname, GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLfixed *", params) +TRACE_GL_VOID(glGetTexParameterxvOES, (GLenum target, GLenum pname, GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLfixed *", params) +TRACE_GL(GLboolean, glIsFenceNV, (GLuint fence), (fence), 1, "GLuint", fence) +TRACE_GL(GLboolean, glIsFramebufferOES, (GLuint framebuffer), (framebuffer), 1, "GLuint", framebuffer) +TRACE_GL(GLboolean, glIsRenderbufferOES, (GLuint renderbuffer), (renderbuffer), 1, "GLuint", renderbuffer) +TRACE_GL(GLboolean, glIsVertexArrayOES, (GLuint array), (array), 1, "GLuint", array) +TRACE_GL_VOID(glLightModelf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param) +TRACE_GL_VOID(glLightModelfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params) +TRACE_GL_VOID(glLightModelx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glLightModelxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glLightModelxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glLightModelxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glLightf, (GLenum light, GLenum pname, GLfloat param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfloat", param) +TRACE_GL_VOID(glLightfv, (GLenum light, GLenum pname, const GLfloat *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfloat *", params) +TRACE_GL_VOID(glLightx, (GLenum light, GLenum pname, GLfixed param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glLightxOES, (GLenum light, GLenum pname, GLfixed param), (light, pname, param), 3, "GLenum", light, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glLightxv, (GLenum light, GLenum pname, const GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glLightxvOES, (GLenum light, GLenum pname, const GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glLineWidthx, (GLfixed width), (width), 1, "GLfixed", width) +TRACE_GL_VOID(glLineWidthxOES, (GLfixed width), (width), 1, "GLfixed", width) +TRACE_GL_VOID(glLoadIdentity, (void), (), 0) +TRACE_GL_VOID(glLoadMatrixf, (const GLfloat *m), (m), 1, "const GLfloat *", m) +TRACE_GL_VOID(glLoadMatrixx, (const GLfixed *m), (m), 1, "const GLfixed *", m) +TRACE_GL_VOID(glLoadMatrixxOES, (const GLfixed *m), (m), 1, "const GLfixed *", m) +TRACE_GL_VOID(glLoadPaletteFromModelViewMatrixOES, (void), (), 0) +TRACE_GL_VOID(glLogicOp, (GLenum opcode), (opcode), 1, "GLenum", opcode) +TRACE_GL(void*, glMapBufferOES, (GLenum target, GLenum access), (target, access), 2, "GLenum", target, "GLenum", access) +TRACE_GL_VOID(glMaterialf, (GLenum face, GLenum pname, GLfloat param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfloat", param) +TRACE_GL_VOID(glMaterialfv, (GLenum face, GLenum pname, const GLfloat *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfloat *", params) +TRACE_GL_VOID(glMaterialx, (GLenum face, GLenum pname, GLfixed param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glMaterialxOES, (GLenum face, GLenum pname, GLfixed param), (face, pname, param), 3, "GLenum", face, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glMaterialxv, (GLenum face, GLenum pname, const GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glMaterialxvOES, (GLenum face, GLenum pname, const GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glMatrixIndexPointerOES, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer) +TRACE_GL_VOID(glMatrixMode, (GLenum mode), (mode), 1, "GLenum", mode) +TRACE_GL_VOID(glMultMatrixf, (const GLfloat *m), (m), 1, "const GLfloat *", m) +TRACE_GL_VOID(glMultMatrixx, (const GLfixed *m), (m), 1, "const GLfixed *", m) +TRACE_GL_VOID(glMultMatrixxOES, (const GLfixed *m), (m), 1, "const GLfixed *", m) +TRACE_GL_VOID(glMultiDrawArraysEXT, (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount), (mode, first, count, primcount), 4, "GLenum", mode, "GLint *", first, "GLsizei *", count, "GLsizei", primcount) +TRACE_GL_VOID(glMultiDrawElementsEXT, (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount), (mode, count, type, indices, primcount), 5, "GLenum", mode, "const GLsizei *", count, "GLenum", type, "const GLvoid* *", indices, "GLsizei", primcount) +TRACE_GL_VOID(glMultiTexCoord4f, (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q), (target, s, t, r, q), 5, "GLenum", target, "GLfloat", s, "GLfloat", t, "GLfloat", r, "GLfloat", q) +TRACE_GL_VOID(glMultiTexCoord4x, (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q), (target, s, t, r, q), 5, "GLenum", target, "GLfixed", s, "GLfixed", t, "GLfixed", r, "GLfixed", q) +TRACE_GL_VOID(glMultiTexCoord4xOES, (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q), (target, s, t, r, q), 5, "GLenum", target, "GLfixed", s, "GLfixed", t, "GLfixed", r, "GLfixed", q) +TRACE_GL_VOID(glNormal3f, (GLfloat nx, GLfloat ny, GLfloat nz), (nx, ny, nz), 3, "GLfloat", nx, "GLfloat", ny, "GLfloat", nz) +TRACE_GL_VOID(glNormal3x, (GLfixed nx, GLfixed ny, GLfixed nz), (nx, ny, nz), 3, "GLfixed", nx, "GLfixed", ny, "GLfixed", nz) +TRACE_GL_VOID(glNormal3xOES, (GLfixed nx, GLfixed ny, GLfixed nz), (nx, ny, nz), 3, "GLfixed", nx, "GLfixed", ny, "GLfixed", nz) +TRACE_GL_VOID(glNormalPointer, (GLenum type, GLsizei stride, const GLvoid *pointer), (type, stride, pointer), 3, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer) +TRACE_GL_VOID(glOrthof, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar) +TRACE_GL_VOID(glOrthofOES, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfloat", left, "GLfloat", right, "GLfloat", bottom, "GLfloat", top, "GLfloat", zNear, "GLfloat", zFar) +TRACE_GL_VOID(glOrthox, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar) +TRACE_GL_VOID(glOrthoxOES, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar), (left, right, bottom, top, zNear, zFar), 6, "GLfixed", left, "GLfixed", right, "GLfixed", bottom, "GLfixed", top, "GLfixed", zNear, "GLfixed", zFar) +TRACE_GL_VOID(glPointParameterf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param) +TRACE_GL_VOID(glPointParameterfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params) +TRACE_GL_VOID(glPointParameterx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glPointParameterxOES, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glPointParameterxv, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glPointParameterxvOES, (GLenum pname, const GLfixed *params), (pname, params), 2, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glPointSize, (GLfloat size), (size), 1, "GLfloat", size) +TRACE_GL_VOID(glPointSizePointerOES, (GLenum type, GLsizei stride, const GLvoid *pointer), (type, stride, pointer), 3, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer) +TRACE_GL_VOID(glPointSizex, (GLfixed size), (size), 1, "GLfixed", size) +TRACE_GL_VOID(glPointSizexOES, (GLfixed size), (size), 1, "GLfixed", size) +TRACE_GL_VOID(glPolygonOffsetx, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units) +TRACE_GL_VOID(glPolygonOffsetxOES, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units) +TRACE_GL_VOID(glPopMatrix, (void), (), 0) +TRACE_GL_VOID(glProgramBinaryOES, (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length), (program, binaryFormat, binary, length), 4, "GLuint", program, "GLenum", binaryFormat, "const GLvoid *", binary, "GLint", length) +TRACE_GL_VOID(glPushMatrix, (void), (), 0) +TRACE_GL(GLbitfield, glQueryMatrixxOES, (GLfixed mantissa[16], GLint exponent[16]), (mantissa, exponent), 2, "GLfixed", mantissa, "GLint", exponent) +TRACE_GL_VOID(glRenderbufferStorageMultisampleIMG, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height) +TRACE_GL_VOID(glRenderbufferStorageOES, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), (target, internalformat, width, height), 4, "GLenum", target, "GLenum", internalformat, "GLsizei", width, "GLsizei", height) +TRACE_GL_VOID(glRotatef, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z), (angle, x, y, z), 4, "GLfloat", angle, "GLfloat", x, "GLfloat", y, "GLfloat", z) +TRACE_GL_VOID(glRotatex, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z) +TRACE_GL_VOID(glRotatexOES, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z) +TRACE_GL_VOID(glSampleCoveragex, (GLclampx value, GLboolean invert), (value, invert), 2, "GLclampx", value, "GLboolean", invert) +TRACE_GL_VOID(glSampleCoveragexOES, (GLclampx value, GLboolean invert), (value, invert), 2, "GLclampx", value, "GLboolean", invert) +TRACE_GL_VOID(glScalef, (GLfloat x, GLfloat y, GLfloat z), (x, y, z), 3, "GLfloat", x, "GLfloat", y, "GLfloat", z) +TRACE_GL_VOID(glScalex, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z) +TRACE_GL_VOID(glScalexOES, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z) +TRACE_GL_VOID(glSelectPerfMonitorCountersAMD, (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList), (monitor, enable, group, numCounters, countersList), 5, "GLuint", monitor, "GLboolean", enable, "GLuint", group, "GLint", numCounters, "GLuint *", countersList) +TRACE_GL_VOID(glSetFenceNV, (GLuint fence, GLenum condition), (fence, condition), 2, "GLuint", fence, "GLenum", condition) +TRACE_GL_VOID(glShadeModel, (GLenum mode), (mode), 1, "GLenum", mode) +TRACE_GL_VOID(glStartTilingQCOM, (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask), (x, y, width, height, preserveMask), 5, "GLuint", x, "GLuint", y, "GLuint", width, "GLuint", height, "GLbitfield", preserveMask) +TRACE_GL(GLboolean, glTestFenceNV, (GLuint fence), (fence), 1, "GLuint", fence) +TRACE_GL_VOID(glTexCoordPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer) +TRACE_GL_VOID(glTexEnvf, (GLenum target, GLenum pname, GLfloat param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfloat", param) +TRACE_GL_VOID(glTexEnvfv, (GLenum target, GLenum pname, const GLfloat *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfloat *", params) +TRACE_GL_VOID(glTexEnvi, (GLenum target, GLenum pname, GLint param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLint", param) +TRACE_GL_VOID(glTexEnviv, (GLenum target, GLenum pname, const GLint *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLint *", params) +TRACE_GL_VOID(glTexEnvx, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glTexEnvxOES, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glTexEnvxv, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glTexEnvxvOES, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glTexGenfOES, (GLenum coord, GLenum pname, GLfloat param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLfloat", param) +TRACE_GL_VOID(glTexGenfvOES, (GLenum coord, GLenum pname, const GLfloat *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLfloat *", params) +TRACE_GL_VOID(glTexGeniOES, (GLenum coord, GLenum pname, GLint param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLint", param) +TRACE_GL_VOID(glTexGenivOES, (GLenum coord, GLenum pname, const GLint *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLint *", params) +TRACE_GL_VOID(glTexGenxOES, (GLenum coord, GLenum pname, GLfixed param), (coord, pname, param), 3, "GLenum", coord, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glTexGenxvOES, (GLenum coord, GLenum pname, const GLfixed *params), (coord, pname, params), 3, "GLenum", coord, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glTexImage3DOES, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels), (target, level, internalformat, width, height, depth, border, format, type, pixels), 10, "GLenum", target, "GLint", level, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLint", border, "GLenum", format, "GLenum", type, "const GLvoid*", pixels) +TRACE_GL_VOID(glTexParameterx, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glTexParameterxOES, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param) +TRACE_GL_VOID(glTexParameterxv, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glTexParameterxvOES, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params) +TRACE_GL_VOID(glTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLenum", type, "const GLvoid*", pixels) +TRACE_GL_VOID(glTranslatef, (GLfloat x, GLfloat y, GLfloat z), (x, y, z), 3, "GLfloat", x, "GLfloat", y, "GLfloat", z) +TRACE_GL_VOID(glTranslatex, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z) +TRACE_GL_VOID(glTranslatexOES, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z) +TRACE_GL(GLboolean, glUnmapBufferOES, (GLenum target), (target), 1, "GLenum", target) +TRACE_GL_VOID(glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer) +TRACE_GL_VOID(glWeightPointerOES, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer), (size, type, stride, pointer), 4, "GLint", size, "GLenum", type, "GLsizei", stride, "const GLvoid *", pointer) diff --git a/opengl/libs/glesv2dbg.h b/opengl/libs/glesv2dbg.h new file mode 100644 index 0000000..8029dce --- /dev/null +++ b/opengl/libs/glesv2dbg.h @@ -0,0 +1,32 @@ +/* + ** 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. + */ + +#ifndef _GLESV2_DBG_H_ +#define _GLESV2_DBG_H_ + +namespace android +{ + struct DbgContext; + + DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks); + void DestroyDbgContext(DbgContext * const dbg); + + void StartDebugServer(unsigned short port); // create and bind socket if haven't already + void StopDebugServer(); // close socket if open + +}; // namespace android + +#endif // #ifndef _GLESV2_DBG_H_ diff --git a/opengl/libs/glesv2dbg_functions.h b/opengl/libs/glesv2dbg_functions.h new file mode 100644 index 0000000..2d70032 --- /dev/null +++ b/opengl/libs/glesv2dbg_functions.h @@ -0,0 +1,381 @@ +extern "C" +{ +GL_ENTRY(void, glActiveTexture, GLenum texture) +GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref) +GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref) +GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref) +GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader) +GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor) +GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar* name) +GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer) +GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer) +GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer) +GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer) +GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer) +GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture) +GL_ENTRY(void, glBindVertexArrayOES, GLuint array) +GL_ENTRY(void, glBlendColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +GL_ENTRY(void, glBlendEquation, GLenum mode ) +GL_ENTRY(void, glBlendEquationOES, GLenum mode) +GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor) +GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) +GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) +GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target) +GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target) +GL_ENTRY(void, glClear, GLbitfield mask) +GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +GL_ENTRY(void, glClearColorx, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) +GL_ENTRY(void, glClearColorxOES, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) +GL_ENTRY(void, glClearDepthf, GLclampf depth) +GL_ENTRY(void, glClearDepthfOES, GLclampf depth) +GL_ENTRY(void, glClearDepthx, GLclampx depth) +GL_ENTRY(void, glClearDepthxOES, GLclampx depth) +GL_ENTRY(void, glClearStencil, GLint s) +GL_ENTRY(void, glClientActiveTexture, GLenum texture) +GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation) +GL_ENTRY(void, glClipPlanefIMG, GLenum p, const GLfloat *eqn) +GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation) +GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation) +GL_ENTRY(void, glClipPlanexIMG, GLenum p, const GLfixed *eqn) +GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation) +GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) +GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) +GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) +GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glCompileShader, GLuint shader) +GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) +GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) +GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glCoverageMaskNV, GLboolean mask) +GL_ENTRY(void, glCoverageOperationNV, GLenum operation) +GL_ENTRY(GLuint, glCreateProgram, void) +GL_ENTRY(GLuint, glCreateShader, GLenum type) +GL_ENTRY(void, glCullFace, GLenum mode) +GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex) +GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers) +GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences) +GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint* framebuffers) +GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers) +GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors) +GL_ENTRY(void, glDeleteProgram, GLuint program) +GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers) +GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers) +GL_ENTRY(void, glDeleteShader, GLuint shader) +GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures) +GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays) +GL_ENTRY(void, glDepthFunc, GLenum func) +GL_ENTRY(void, glDepthMask, GLboolean flag) +GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar) +GL_ENTRY(void, glDepthRangefOES, GLclampf zNear, GLclampf zFar) +GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar) +GL_ENTRY(void, glDepthRangexOES, GLclampx zNear, GLclampx zFar) +GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader) +GL_ENTRY(void, glDisable, GLenum cap) +GL_ENTRY(void, glDisableClientState, GLenum array) +GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl) +GL_ENTRY(void, glDisableVertexAttribArray, GLuint index) +GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments) +GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count) +GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) +GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) +GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords) +GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height) +GL_ENTRY(void, glDrawTexivOES, const GLint *coords) +GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) +GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords) +GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) +GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords) +GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glEnable, GLenum cap) +GL_ENTRY(void, glEnableClientState, GLenum array) +GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl) +GL_ENTRY(void, glEnableVertexAttribArray, GLuint index) +GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor) +GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask) +GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid **params) +GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers) +GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) +GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length) +GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms) +GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers) +GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders) +GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) +GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels) +GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures) +GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program) +GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glFinish, void) +GL_ENTRY(void, glFinishFenceNV, GLuint fence) +GL_ENTRY(void, glFlush, void) +GL_ENTRY(void, glFogf, GLenum pname, GLfloat param) +GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glFogx, GLenum pname, GLfixed param) +GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) +GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) +GL_ENTRY(void, glFrontFace, GLenum mode) +GL_ENTRY(void, glFrustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glFrustumfOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glFrustumx, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glFrustumxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers) +GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences) +GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers) +GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers) +GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors) +GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers) +GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers) +GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures) +GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays) +GL_ENTRY(void, glGenerateMipmap, GLenum target) +GL_ENTRY(void, glGenerateMipmapOES, GLenum target) +GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +GL_ENTRY(int, glGetAttribLocation, GLuint program, const GLchar* name) +GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params) +GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, GLvoid ** params) +GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat eqn[4]) +GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat eqn[4]) +GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed eqn[4]) +GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed eqn[4]) +GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString) +GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls) +GL_ENTRY(GLenum, glGetError, void) +GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params) +GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params) +GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params) +GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params) +GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) +GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, GLvoid *data) +GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString) +GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) +GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString) +GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups) +GL_ENTRY(void, glGetPointerv, GLenum pname, GLvoid **params) +GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) +GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params) +GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params) +GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params) +GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params) +GL_ENTRY(const GLubyte *, glGetString, GLenum name) +GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexEnviv, GLenum env, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexEnvxvOES, GLenum env, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params) +GL_ENTRY(int, glGetUniformLocation, GLuint program, const GLchar* name) +GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat* params) +GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint* params) +GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, GLvoid** pointer) +GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params) +GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params) +GL_ENTRY(void, glHint, GLenum target, GLenum mode) +GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer) +GL_ENTRY(GLboolean, glIsEnabled, GLenum cap) +GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence) +GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer) +GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer) +GL_ENTRY(GLboolean, glIsProgram, GLuint program) +GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer) +GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer) +GL_ENTRY(GLboolean, glIsShader, GLuint shader) +GL_ENTRY(GLboolean, glIsTexture, GLuint texture) +GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array) +GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param) +GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param) +GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLineWidth, GLfloat width) +GL_ENTRY(void, glLineWidthx, GLfixed width) +GL_ENTRY(void, glLineWidthxOES, GLfixed width) +GL_ENTRY(void, glLinkProgram, GLuint program) +GL_ENTRY(void, glLoadIdentity, void) +GL_ENTRY(void, glLoadMatrixf, const GLfloat *m) +GL_ENTRY(void, glLoadMatrixx, const GLfixed *m) +GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m) +GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void) +GL_ENTRY(void, glLogicOp, GLenum opcode) +GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access) +GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param) +GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param) +GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param) +GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glMatrixMode, GLenum mode) +GL_ENTRY(void, glMultMatrixf, const GLfloat *m) +GL_ENTRY(void, glMultMatrixx, const GLfixed *m) +GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m) +GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) +GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) +GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) +GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz) +GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz) +GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz) +GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glOrthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glOrthofOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glOrthox, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glOrthoxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param) +GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param) +GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param) +GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glPointSize, GLfloat size) +GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glPointSizex, GLfixed size) +GL_ENTRY(void, glPointSizexOES, GLfixed size) +GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units) +GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units) +GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units) +GL_ENTRY(void, glPopMatrix, void) +GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length) +GL_ENTRY(void, glPushMatrix, void) +GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16]) +GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) +GL_ENTRY(void, glReleaseShaderCompiler, void) +GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert) +GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert) +GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert) +GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList) +GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition) +GL_ENTRY(void, glShadeModel, GLenum mode) +GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) +GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask) +GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask) +GL_ENTRY(void, glStencilMask, GLuint mask) +GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask) +GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass) +GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence) +GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param) +GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) +GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glUniform1f, GLint location, GLfloat x) +GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat* v) +GL_ENTRY(void, glUniform1i, GLint location, GLint x) +GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint* v) +GL_ENTRY(void, glUniform2f, GLint location, GLfloat x, GLfloat y) +GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat* v) +GL_ENTRY(void, glUniform2i, GLint location, GLint x, GLint y) +GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint* v) +GL_ENTRY(void, glUniform3f, GLint location, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat* v) +GL_ENTRY(void, glUniform3i, GLint location, GLint x, GLint y, GLint z) +GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint* v) +GL_ENTRY(void, glUniform4f, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat* v) +GL_ENTRY(void, glUniform4i, GLint location, GLint x, GLint y, GLint z, GLint w) +GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint* v) +GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target) +GL_ENTRY(void, glUseProgram, GLuint program) +GL_ENTRY(void, glValidateProgram, GLuint program) +GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x) +GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values) +GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y) +GL_ENTRY(void, glVertexAttrib2fv, GLuint indx, const GLfloat* values) +GL_ENTRY(void, glVertexAttrib3f, GLuint indx, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glVertexAttrib3fv, GLuint indx, const GLfloat* values) +GL_ENTRY(void, glVertexAttrib4f, GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +GL_ENTRY(void, glVertexAttrib4fv, GLuint indx, const GLfloat* values) +GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) + + +} diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk index 384966c..e8b6c57 100644 --- a/opengl/tests/gl2_jni/Android.mk +++ b/opengl/tests/gl2_jni/Android.mk @@ -44,7 +44,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libgl2jni -LOCAL_PRELINK_MODULE := false + include $(BUILD_SHARED_LIBRARY) diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk index f1bd31d..4acd91f 100644 --- a/opengl/tests/gl_jni/Android.mk +++ b/opengl/tests/gl_jni/Android.mk @@ -46,7 +46,7 @@ LOCAL_MODULE := libgljni LOCAL_ARM_MODE := arm -LOCAL_PRELINK_MODULE := false + include $(BUILD_SHARED_LIBRARY) diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk index dd75a74..4b79569 100644 --- a/opengl/tests/gl_perfapp/Android.mk +++ b/opengl/tests/gl_perfapp/Android.mk @@ -47,7 +47,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libglperf -LOCAL_PRELINK_MODULE := false + include $(BUILD_SHARED_LIBRARY) diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk index 995a5d7..f1a998a 100644 --- a/opengl/tests/gldual/Android.mk +++ b/opengl/tests/gldual/Android.mk @@ -44,7 +44,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libgldualjni -LOCAL_PRELINK_MODULE := false + include $(BUILD_SHARED_LIBRARY) diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk index 6312970..e4d7e28 100644 --- a/opengl/tests/hwc/Android.mk +++ b/opengl/tests/hwc/Android.mk @@ -29,7 +29,7 @@ LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport LOCAL_STATIC_LIBRARIES += libglTest -LOCAL_PRELINK_MODULE := false + include $(BUILD_STATIC_LIBRARY) diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk index 7542ac4..ac1e183 100644 --- a/opengl/tests/lib/Android.mk +++ b/opengl/tests/lib/Android.mk @@ -27,6 +27,6 @@ LOCAL_C_INCLUDES += system/extras/tests/include \ LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport -LOCAL_PRELINK_MODULE := false + include $(BUILD_STATIC_LIBRARY) diff --git a/packages/DefaultContainerService/jni/Android.mk b/packages/DefaultContainerService/jni/Android.mk index a2febec..79ff451 100644 --- a/packages/DefaultContainerService/jni/Android.mk +++ b/packages/DefaultContainerService/jni/Android.mk @@ -18,7 +18,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_PRELINK_MODULE := false + LOCAL_SRC_FILES := \ com_android_defcontainer_MeasurementUtils.cpp diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 337593f..15c1653 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -47,7 +47,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipException; @@ -117,7 +117,7 @@ public class DefaultContainerService extends IntentService { * @return Returns PackageInfoLite object containing * the package info and recommended app location. */ - public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags) { + public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags, long threshold) { PackageInfoLite ret = new PackageInfoLite(); if (fileUri == null) { Log.i(TAG, "Invalid package uri " + fileUri); @@ -131,15 +131,9 @@ public class DefaultContainerService extends IntentService { return ret; } String archiveFilePath = fileUri.getPath(); - PackageParser packageParser = new PackageParser(archiveFilePath); - File sourceFile = new File(archiveFilePath); DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); - PackageParser.PackageLite pkg = packageParser.parsePackageLite( - archiveFilePath, 0); - // Nuke the parser reference right away and force a gc - packageParser = null; - Runtime.getRuntime().gc(); + PackageParser.PackageLite pkg = PackageParser.parsePackageLite(archiveFilePath, 0); if (pkg == null) { Log.w(TAG, "Failed to parse package"); ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; @@ -147,12 +141,22 @@ public class DefaultContainerService extends IntentService { } ret.packageName = pkg.packageName; ret.installLocation = pkg.installLocation; - ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath, flags); + ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, + archiveFilePath, flags, threshold); return ret; } - public boolean checkFreeStorage(boolean external, Uri fileUri) { - return checkFreeStorageInner(external, fileUri); + @Override + public boolean checkInternalFreeStorage(Uri packageUri, long threshold) + throws RemoteException { + final File apkFile = new File(packageUri.getPath()); + return isUnderInternalThreshold(apkFile, threshold); + } + + @Override + public boolean checkExternalFreeStorage(Uri packageUri) throws RemoteException { + final File apkFile = new File(packageUri.getPath()); + return isUnderExternalThreshold(apkFile); } public ObbInfo getObbInfo(String filename) { @@ -225,41 +229,15 @@ public class DefaultContainerService extends IntentService { String codePath = packageURI.getPath(); File codeFile = new File(codePath); - // Calculate size of container needed to hold base APK. - long sizeBytes = codeFile.length(); - - // Check all the native files that need to be copied and add that to the container size. - ZipFile zipFile; - List<Pair<ZipEntry, String>> nativeFiles; - try { - zipFile = new ZipFile(codeFile); - - nativeFiles = new LinkedList<Pair<ZipEntry, String>>(); - - NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); + // Native files we need to copy to the container. + List<Pair<ZipEntry, String>> nativeFiles = new ArrayList<Pair<ZipEntry, String>>(); - final int N = nativeFiles.size(); - for (int i = 0; i < N; i++) { - final Pair<ZipEntry, String> entry = nativeFiles.get(i); - - /* - * Note that PackageHelper.createSdDir adds a 1MB padding on - * our claimed size, so we don't have to worry about block - * alignment here. - */ - sizeBytes += entry.first.getSize(); - } - } catch (ZipException e) { - Log.w(TAG, "Failed to extract data from package file", e); - return null; - } catch (IOException e) { - Log.w(TAG, "Failed to cache package shared libs", e); - return null; - } + // Calculate size of container needed to hold base APK. + final int sizeMb = calculateContainerSize(codeFile, nativeFiles); // Create new container String newCachePath = null; - if ((newCachePath = PackageHelper.createSdDir(sizeBytes, newCid, key, Process.myUid())) == null) { + if ((newCachePath = PackageHelper.createSdDir(sizeMb, newCid, key, Process.myUid())) == null) { Log.e(TAG, "Failed to create container " + newCid); return null; } @@ -274,6 +252,8 @@ public class DefaultContainerService extends IntentService { } try { + ZipFile zipFile = new ZipFile(codeFile); + File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); sharedLibraryDir.mkdir(); @@ -386,163 +366,196 @@ public class DefaultContainerService extends IntentService { return true; } - // Constants related to app heuristics - // No-installation limit for internal flash: 10% or less space available - private static final double LOW_NAND_FLASH_TRESHOLD = 0.1; + private static final int PREFER_INTERNAL = 1; + private static final int PREFER_EXTERNAL = 2; - // No-installation limit for internal flash: 150MB or less space available - private static final long NAND_MIN_FREE_SPACE = (1024L * 1024L * 150L); - - // SD-to-internal app size threshold: currently set to 1 MB - private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); - private static final int ERR_LOC = -1; - - private int recommendAppInstallLocation(int installLocation, - String archiveFilePath, int flags) { - boolean checkInt = false; - boolean checkExt = false; + private int recommendAppInstallLocation(int installLocation, String archiveFilePath, int flags, + long threshold) { + int prefer; boolean checkBoth = false; + check_inner : { - // Check flags. + /* + * Explicit install flags should override the manifest settings. + */ if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { - // Check for forward locked app - checkInt = true; + /* + * Forward-locked applications cannot be installed on SD card, + * so only allow checking internal storage. + */ + prefer = PREFER_INTERNAL; break check_inner; } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) { - // Explicit flag to install internally. - // Check internal storage and return - checkInt = true; + prefer = PREFER_INTERNAL; break check_inner; } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) { - // Explicit flag to install externally. - // Check external storage and return - checkExt = true; + prefer = PREFER_EXTERNAL; break check_inner; } - // Check for manifest option + + /* No install flags. Check for manifest option. */ if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { - checkInt = true; + prefer = PREFER_INTERNAL; break check_inner; } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { - checkExt = true; + prefer = PREFER_EXTERNAL; checkBoth = true; break check_inner; } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) { - checkInt = true; + // We default to preferring internal storage. + prefer = PREFER_INTERNAL; checkBoth = true; break check_inner; } + // Pick user preference int installPreference = Settings.System.getInt(getApplicationContext() .getContentResolver(), Settings.Secure.DEFAULT_INSTALL_LOCATION, PackageHelper.APP_INSTALL_AUTO); if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) { - checkInt = true; + prefer = PREFER_INTERNAL; break check_inner; } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) { - checkExt = true; + prefer = PREFER_EXTERNAL; break check_inner; } - // Fall back to default policy if nothing else is specified. - checkInt = true; + + /* + * Fall back to default policy of internal-only if nothing else is + * specified. + */ + prefer = PREFER_INTERNAL; } - // Package size = code size + cache size + data size - // If code size > 1 MB, install on SD card. - // Else install on internal NAND flash, unless space on NAND is less than 10% - String status = Environment.getExternalStorageState(); - long availSDSize = -1; - boolean mediaAvailable = false; - final boolean mediaEmulated = Environment.isExternalStorageEmulated(); - if (!mediaEmulated && status.equals(Environment.MEDIA_MOUNTED)) { - StatFs sdStats = new StatFs( - Environment.getExternalStorageDirectory().getPath()); - availSDSize = (long)sdStats.getAvailableBlocks() * - (long)sdStats.getBlockSize(); - mediaAvailable = true; + final boolean emulated = Environment.isExternalStorageEmulated(); + + final File apkFile = new File(archiveFilePath); + + boolean fitsOnInternal = false; + if (checkBoth || prefer == PREFER_INTERNAL) { + fitsOnInternal = isUnderInternalThreshold(apkFile, threshold); } - StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); - long totalInternalSize = (long)internalStats.getBlockCount() * - (long)internalStats.getBlockSize(); - long availInternalSize = (long)internalStats.getAvailableBlocks() * - (long)internalStats.getBlockSize(); - - double pctNandFree = (double)availInternalSize / (double)totalInternalSize; - - File apkFile = new File(archiveFilePath); - long pkgLen = apkFile.length(); - - // To make final copy - long reqInstallSize = pkgLen; - // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now. - long reqInternalSize = 0; - boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); - boolean intAvailOk = (reqInstallSize + reqInternalSize) < (availInternalSize - NAND_MIN_FREE_SPACE); + boolean fitsOnSd = false; - if (mediaAvailable && (reqInstallSize < availSDSize)) { - // If we do not have an internal size requirement - // don't do a threshold check. - if (reqInternalSize == 0) { - fitsOnSd = true; - } else if ((reqInternalSize < availInternalSize) && intThresholdOk) { - fitsOnSd = true; - } + if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) { + fitsOnSd = isUnderExternalThreshold(apkFile); } - boolean fitsOnInt = intThresholdOk || intAvailOk; - if (checkInt) { - // Check for internal memory availability - if (fitsOnInt) { + + if (prefer == PREFER_INTERNAL) { + if (fitsOnInternal) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } - } else if (checkExt) { + } else if (!emulated && prefer == PREFER_EXTERNAL) { if (fitsOnSd) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } } + if (checkBoth) { - // Check for internal first - if (fitsOnInt) { + if (fitsOnInternal) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; - } - // Check for external next - if (fitsOnSd) { + } else if (!emulated && fitsOnSd) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } } - if (!mediaEmulated && (checkExt || checkBoth) && !mediaAvailable) { + + /* + * If they requested to be on the external media by default, return that + * the media was unavailable. Otherwise, indicate there was insufficient + * storage space available. + */ + if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL) + && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE; + } else { + return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } - return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } - private boolean checkFreeStorageInner(boolean external, Uri packageURI) { - File apkFile = new File(packageURI.getPath()); - long size = apkFile.length(); - if (external) { - String status = Environment.getExternalStorageState(); - long availSDSize = -1; - if (status.equals(Environment.MEDIA_MOUNTED)) { - StatFs sdStats = new StatFs( - Environment.getExternalStorageDirectory().getPath()); - availSDSize = (long)sdStats.getAvailableBlocks() * - (long)sdStats.getBlockSize(); + private boolean isUnderInternalThreshold(File apkFile, long threshold) { + final long size = apkFile.length(); + + final StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); + final long availInternalSize = (long) internalStats.getAvailableBlocks() + * (long) internalStats.getBlockSize(); + + return (availInternalSize - size) > threshold; + } + + + private boolean isUnderExternalThreshold(File apkFile) { + if (Environment.isExternalStorageEmulated()) { + return false; + } + + final int sizeMb = calculateContainerSize(apkFile, null); + + final int availSdMb; + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + StatFs sdStats = new StatFs(Environment.getExternalStorageDirectory().getPath()); + long availSdSize = (long) (sdStats.getAvailableBlocks() * sdStats.getBlockSize()); + availSdMb = (int) (availSdSize >> 20); + } else { + availSdMb = -1; + } + + return availSdMb > sizeMb; + } + + /** + * Calculate the container size for an APK. Takes into account the + * + * @param apkFile file from which to calculate size + * @return size in megabytes (2^20 bytes) + */ + private int calculateContainerSize(File apkFile, List<Pair<ZipEntry, String>> outFiles) { + // Calculate size of container needed to hold base APK. + long sizeBytes = apkFile.length(); + + // Check all the native files that need to be copied and add that to the + // container size. + ZipFile zipFile; + final List<Pair<ZipEntry, String>> nativeFiles; + try { + zipFile = new ZipFile(apkFile); + + if (outFiles != null) { + nativeFiles = outFiles; + } else { + nativeFiles = new ArrayList<Pair<ZipEntry, String>>(); + } + + NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); + + final int N = nativeFiles.size(); + for (int i = 0; i < N; i++) { + final Pair<ZipEntry, String> entry = nativeFiles.get(i); + + /* + * Note a 1MB padding is added to the claimed size, so we don't + * have to worry about block alignment here. + */ + sizeBytes += entry.first.getSize(); } - return availSDSize > size; + } catch (ZipException e) { + Log.w(TAG, "Failed to extract data from package file", e); + } catch (IOException e) { + Log.w(TAG, "Failed to cache package shared libs", e); } - StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); - long totalInternalSize = (long)internalStats.getBlockCount() * - (long)internalStats.getBlockSize(); - long availInternalSize = (long)internalStats.getAvailableBlocks() * - (long)internalStats.getBlockSize(); - - double pctNandFree = (double)availInternalSize / (double)totalInternalSize; - // To make final copy - long reqInstallSize = size; - // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now. - long reqInternalSize = 0; - boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); - boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize); - return intThresholdOk && intAvailOk; + + int sizeMb = (int) (sizeBytes >> 20); + if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) { + sizeMb++; + } + + /* + * Add buffer size because we don't have a good way to determine the + * real FAT size. Your FAT size varies with how many directory entries + * you need, how big the whole filesystem is, and other such headaches. + */ + sizeMb++; + + return sizeMb; } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 64857ed..36e6b8e 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -903,7 +903,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } private void reopenMenu(boolean toggleMenuMode) { - if (mActionBar != null) { + if (mActionBar != null && mActionBar.isOverflowReserved()) { final Callback cb = getCallback(); if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) { if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) { diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 2b08ab5..2702242 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1738,7 +1738,10 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this); tracksToRemove->add(track); // indicate to client process that the track was disabled because of underrun - cblk->flags |= CBLK_DISABLED_ON; + { + AutoMutex _l(cblk->lock); + cblk->flags |= CBLK_DISABLED_ON; + } } else if (mixerStatus != MIXER_TRACKS_READY) { mixerStatus = MIXER_TRACKS_ENABLED; } @@ -1787,10 +1790,9 @@ void AudioFlinger::MixerThread::invalidateTracks(int streamType) for (size_t i = 0; i < size; i++) { sp<Track> t = mTracks[i]; if (t->type() == streamType) { - t->mCblk->lock.lock(); + AutoMutex _lcblk(t->mCblk->lock); t->mCblk->flags |= CBLK_INVALID_ON; t->mCblk->cv.signal(); - t->mCblk->lock.unlock(); } } } @@ -2948,6 +2950,7 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const { if (mCblk->framesReady() >= mCblk->frameCount || (mCblk->flags & CBLK_FORCEREADY_MSK)) { + AutoMutex _l(mCblk->lock); mFillingUpStatus = FS_FILLED; mCblk->flags &= ~CBLK_FORCEREADY_MSK; return true; @@ -3063,19 +3066,18 @@ void AudioFlinger::PlaybackThread::Track::flush() // STOPPED state mState = STOPPED; - mCblk->lock.lock(); // NOTE: reset() will reset cblk->user and cblk->server with // the risk that at the same time, the AudioMixer is trying to read // data. In this case, getNextBuffer() would return a NULL pointer // as audio buffer => the AudioMixer code MUST always test that pointer // returned by getNextBuffer() is not NULL! reset(); - mCblk->lock.unlock(); } } void AudioFlinger::PlaybackThread::Track::reset() { + AutoMutex _l(mCblk->lock); // Do not reset twice to avoid discarding data written just after a flush and before // the audioflinger thread detects the track is stopped. if (!mResetDone) { @@ -3209,10 +3211,13 @@ void AudioFlinger::RecordThread::RecordTrack::stop() if (thread != 0) { RecordThread *recordThread = (RecordThread *)thread.get(); recordThread->stop(this); - TrackBase::reset(); - // Force overerrun condition to avoid false overrun callback until first data is - // read from buffer - mCblk->flags |= CBLK_UNDERRUN_ON; + { + AutoMutex _l(mCblk->lock); + TrackBase::reset(); + // Force overerrun condition to avoid false overrun callback until first data is + // read from buffer + mCblk->flags |= CBLK_UNDERRUN_ON; + } } } diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index b52fc69..14f1e8b 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -49,7 +49,6 @@ LOCAL_SHARED_LIBRARIES:= \ libcutils \ libmedia \ libcamera_client \ - libsurfaceflinger_client \ libgui LOCAL_MODULE:= libcameraservice diff --git a/services/camera/tests/CameraServiceTest/Android.mk b/services/camera/tests/CameraServiceTest/Android.mk index cf4e42f..cf7302a 100644 --- a/services/camera/tests/CameraServiceTest/Android.mk +++ b/services/camera/tests/CameraServiceTest/Android.mk @@ -19,7 +19,7 @@ LOCAL_SHARED_LIBRARIES += \ libutils \ libui \ libcamera_client \ - libsurfaceflinger_client + libgui # Disable it because the ISurface interface may change, and before we have a # chance to fix this test, we don't want to break normal builds. diff --git a/services/input/Android.mk b/services/input/Android.mk index d7b61fc..96431bc 100644 --- a/services/input/Android.mk +++ b/services/input/Android.mk @@ -29,8 +29,8 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libhardware \ libhardware_legacy \ - libsurfaceflinger_client \ libskia \ + libgui \ libui LOCAL_C_INCLUDES := \ diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 853dda4..7625adb 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -127,9 +127,11 @@ EventHub::EventHub(void) : mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1), mOpeningDevices(0), mClosingDevices(0), mOpened(false), mNeedToSendFinishedDeviceScan(false), - mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) { + mInputFdIndex(1) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); + memset(mSwitches, 0, sizeof(mSwitches)); + mNumCpus = sysconf(_SC_NPROCESSORS_ONLN); } EventHub::~EventHub(void) { @@ -445,17 +447,10 @@ EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { return NULL; } -bool EventHub::getEvent(RawEvent* outEvent) { - outEvent->deviceId = 0; - outEvent->type = 0; - outEvent->scanCode = 0; - outEvent->keyCode = 0; - outEvent->flags = 0; - outEvent->value = 0; - outEvent->when = 0; - - // Note that we only allow one caller to getEvent(), so don't need +size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { + // Note that we only allow one caller to getEvents(), so don't need // to do locking here... only when adding/removing devices. + assert(bufferSize >= 1); if (!mOpened) { mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR; @@ -463,99 +458,62 @@ bool EventHub::getEvent(RawEvent* outEvent) { mNeedToSendFinishedDeviceScan = true; } + struct input_event readBuffer[bufferSize]; + + RawEvent* event = buffer; + size_t capacity = bufferSize; for (;;) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + // Report any devices that had last been added/removed. - if (mClosingDevices != NULL) { + while (mClosingDevices) { Device* device = mClosingDevices; LOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.string()); mClosingDevices = device->next; - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = DEVICE_REMOVED; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); + event->when = now; + event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + event->type = DEVICE_REMOVED; + event += 1; delete device; mNeedToSendFinishedDeviceScan = true; - return true; + if (--capacity == 0) { + break; + } } - if (mOpeningDevices != NULL) { + while (mOpeningDevices != NULL) { Device* device = mOpeningDevices; LOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.string()); mOpeningDevices = device->next; - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = DEVICE_ADDED; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); + event->when = now; + event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + event->type = DEVICE_ADDED; + event += 1; mNeedToSendFinishedDeviceScan = true; - return true; + if (--capacity == 0) { + break; + } } if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; - outEvent->type = FINISHED_DEVICE_SCAN; - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); - return true; + event->when = now; + event->type = FINISHED_DEVICE_SCAN; + event += 1; + if (--capacity == 0) { + break; + } } // Grab the next input event. + // mInputFdIndex is initially 1 because index 0 is used for inotify. bool deviceWasRemoved = false; - for (;;) { - // Consume buffered input events, if any. - if (mInputBufferIndex < mInputBufferCount) { - const struct input_event& iev = mInputBufferData[mInputBufferIndex++]; - const Device* device = mDevices[mInputFdIndex]; - - LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(), - (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value); - if (device->id == mBuiltInKeyboardId) { - outEvent->deviceId = 0; - } else { - outEvent->deviceId = device->id; - } - outEvent->type = iev.type; - outEvent->scanCode = iev.code; - outEvent->flags = 0; - if (iev.type == EV_KEY) { - outEvent->keyCode = AKEYCODE_UNKNOWN; - if (device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code, - &outEvent->keyCode, &outEvent->flags); - LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", - iev.code, outEvent->keyCode, outEvent->flags, err); - } - } else { - outEvent->keyCode = iev.code; - } - outEvent->value = iev.value; - - // Use an event timestamp in the same timebase as - // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis() - // as expected by the rest of the system. - outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); - return true; - } - - // Finish reading all events from devices identified in previous poll(). - // This code assumes that mInputDeviceIndex is initially 0 and that the - // revents member of pollfd is initialized to 0 when the device is first added. - // Since mFds[0] is used for inotify, we process regular events starting at index 1. - mInputFdIndex += 1; - if (mInputFdIndex >= mFds.size()) { - break; - } - + while (mInputFdIndex < mFds.size()) { const struct pollfd& pfd = mFds[mInputFdIndex]; if (pfd.revents & POLLIN) { - int32_t readSize = read(pfd.fd, mInputBufferData, - sizeof(struct input_event) * INPUT_BUFFER_SIZE); + int32_t readSize = read(pfd.fd, readBuffer, sizeof(struct input_event) * capacity); if (readSize < 0) { if (errno == ENODEV) { deviceWasRemoved = true; @@ -566,11 +524,43 @@ bool EventHub::getEvent(RawEvent* outEvent) { } } else if ((readSize % sizeof(struct input_event)) != 0) { LOGE("could not get event (wrong size: %d)", readSize); + } else if (readSize == 0) { // eof + deviceWasRemoved = true; + break; } else { - mInputBufferCount = size_t(readSize) / sizeof(struct input_event); - mInputBufferIndex = 0; + const Device* device = mDevices[mInputFdIndex]; + int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + + size_t count = size_t(readSize) / sizeof(struct input_event); + for (size_t i = 0; i < count; i++) { + const struct input_event& iev = readBuffer[i]; + LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d", + device->path.string(), + (int) iev.time.tv_sec, (int) iev.time.tv_usec, + iev.type, iev.code, iev.value); + + event->when = now; + event->deviceId = deviceId; + event->type = iev.type; + event->scanCode = iev.code; + event->value = iev.value; + event->keyCode = AKEYCODE_UNKNOWN; + event->flags = 0; + if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code, + &event->keyCode, &event->flags); + LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", + iev.code, event->keyCode, event->flags, err); + } + event += 1; + } + capacity -= count; + if (capacity == 0) { + break; + } } } + mInputFdIndex += 1; } // Handle the case where a device has been removed but INotify has not yet noticed. @@ -586,10 +576,16 @@ bool EventHub::getEvent(RawEvent* outEvent) { if(mFds[0].revents & POLLIN) { readNotify(mFds[0].fd); mFds.editItemAt(0).revents = 0; + mInputFdIndex = mFds.size(); continue; // report added or removed devices immediately } #endif + // Return now if we have collected any events, otherwise poll. + if (event != buffer) { + break; + } + // Poll for events. Mind the wake lock dance! // We hold a wake lock at all times except during poll(). This works due to some // subtle choreography. When a device driver has pending (unread) events, it acquires @@ -598,22 +594,46 @@ bool EventHub::getEvent(RawEvent* outEvent) { // when this happens, the EventHub holds onto its own user wake lock while the client // is processing events. Thus the system can only sleep if there are no events // pending or currently being processed. + // + // The timeout is advisory only. If the device is asleep, it will not wake just to + // service the timeout. release_wake_lock(WAKE_LOCK_ID); - int pollResult = poll(mFds.editArray(), mFds.size(), -1); + int pollResult = poll(mFds.editArray(), mFds.size(), timeoutMillis); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); - if (pollResult <= 0) { + if (pollResult == 0) { + break; // timed out + } + if (pollResult < 0) { + // Sleep after errors to avoid locking up the system. + // Hopefully the error is transient. if (errno != EINTR) { LOGW("poll failed (errno=%d)\n", errno); usleep(100000); } + } else { + // On an SMP system, it is possible for the framework to read input events + // faster than the kernel input device driver can produce a complete packet. + // Because poll() wakes up as soon as the first input event becomes available, + // the framework will often end up reading one event at a time until the + // packet is complete. Instead of one call to read() returning 71 events, + // it could take 71 calls to read() each returning 1 event. + // + // Sleep for a short period of time after waking up from the poll() to give + // the kernel time to finish writing the entire packet of input events. + if (mNumCpus > 1) { + usleep(250); + } } // Prepare to process all of the FDs we just polled. - mInputFdIndex = 0; + mInputFdIndex = 1; } + + // All done, return the number of events we read. + return event - buffer; } /* diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 7053a94..4d26a95 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -157,6 +157,8 @@ public: // Sent when all added/removed devices from the most recent scan have been reported. // This event is always sent at least once. FINISHED_DEVICE_SCAN = 0x30000000, + + FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, }; virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; @@ -181,13 +183,18 @@ public: virtual void addExcludedDevice(const char* deviceName) = 0; /* - * Wait for the next event to become available and return it. + * Wait for events to become available and returns them. * After returning, the EventHub holds onto a wake lock until the next call to getEvent. * This ensures that the device will not go to sleep while the event is being processed. * If the device needs to remain awake longer than that, then the caller is responsible * for taking care of it (say, by poking the power manager user activity timer). + * + * The timeout is advisory only. If the device is asleep, it will not wake just to + * service the timeout. + * + * Returns the number of events obtained, or 0 if the timeout expired. */ - virtual bool getEvent(RawEvent* outEvent) = 0; + virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; /* * Query current input state. @@ -244,7 +251,7 @@ public: virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; - virtual bool getEvent(RawEvent* outEvent); + virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); virtual bool hasLed(int32_t deviceId, int32_t led) const; virtual void setLedState(int32_t deviceId, int32_t led, bool on); @@ -331,11 +338,11 @@ private: // device ids that report particular switches. int32_t mSwitches[SW_MAX + 1]; - static const int INPUT_BUFFER_SIZE = 64; - struct input_event mInputBufferData[INPUT_BUFFER_SIZE]; - size_t mInputBufferIndex; - size_t mInputBufferCount; + // The index of the next file descriptor that needs to be read. size_t mInputFdIndex; + + // Set to the number of CPUs. + int32_t mNumCpus; }; }; // namespace android diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 19295e6..feca58d 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -48,6 +48,9 @@ // Log debug messages about the app switch latency optimization. #define DEBUG_APP_SWITCH 0 +// Log debug messages about hover events. +#define DEBUG_HOVER 0 + #include "InputDispatcher.h" #include <cutils/log.h> @@ -115,7 +118,9 @@ static bool isValidMotionAction(int32_t action, size_t pointerCount) { case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_OUTSIDE: + case AMOTION_EVENT_ACTION_HOVER_ENTER: case AMOTION_EVENT_ACTION_HOVER_MOVE: + case AMOTION_EVENT_ACTION_HOVER_EXIT: case AMOTION_EVENT_ACTION_SCROLL: return true; case AMOTION_EVENT_ACTION_POINTER_DOWN: @@ -185,7 +190,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mFocusedWindow(NULL), mFocusedApplication(NULL), mCurrentInputTargetsValid(false), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { + mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE), + mLastHoverWindow(NULL) { mLooper = new Looper(false); mInboundQueue.headSentinel.refCount = -1; @@ -238,15 +244,7 @@ void InputDispatcher::dispatchOnce() { // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t currentTime = now(); - int32_t timeoutMillis; - if (nextWakeupTime > currentTime) { - uint64_t timeout = uint64_t(nextWakeupTime - currentTime); - timeout = (timeout + 999999LL) / 1000000LL; - timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout); - } else { - timeoutMillis = 0; - } - + int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis); } @@ -845,10 +843,11 @@ bool InputDispatcher::dispatchMotionLocked( bool conflictingPointerActions = false; if (! mCurrentInputTargetsValid) { int32_t injectionResult; + const MotionSample* splitBatchAfterSample = NULL; if (isPointerEvent) { // Pointer event. (eg. touchscreen) injectionResult = findTouchedWindowTargetsLocked(currentTime, - entry, nextWakeupTime, &conflictingPointerActions); + entry, nextWakeupTime, &conflictingPointerActions, &splitBatchAfterSample); } else { // Non touch event. (eg. trackball) injectionResult = findFocusedWindowTargetsLocked(currentTime, @@ -865,6 +864,41 @@ bool InputDispatcher::dispatchMotionLocked( addMonitoringTargetsLocked(); commitTargetsLocked(); + + // Unbatch the event if necessary by splitting it into two parts after the + // motion sample indicated by splitBatchAfterSample. + if (splitBatchAfterSample && splitBatchAfterSample->next) { +#if DEBUG_BATCHING + uint32_t originalSampleCount = entry->countSamples(); +#endif + MotionSample* nextSample = splitBatchAfterSample->next; + MotionEntry* nextEntry = mAllocator.obtainMotionEntry(nextSample->eventTime, + entry->deviceId, entry->source, entry->policyFlags, + entry->action, entry->flags, entry->metaState, entry->edgeFlags, + entry->xPrecision, entry->yPrecision, entry->downTime, + entry->pointerCount, entry->pointerIds, nextSample->pointerCoords); + if (nextSample != entry->lastSample) { + nextEntry->firstSample.next = nextSample->next; + nextEntry->lastSample = entry->lastSample; + } + mAllocator.freeMotionSample(nextSample); + + entry->lastSample = const_cast<MotionSample*>(splitBatchAfterSample); + entry->lastSample->next = NULL; + + if (entry->injectionState) { + nextEntry->injectionState = entry->injectionState; + entry->injectionState->refCount += 1; + } + +#if DEBUG_BATCHING + LOGD("Split batch of %d samples into two parts, first part has %d samples, " + "second part has %d samples.", originalSampleCount, + entry->countSamples(), nextEntry->countSamples()); +#endif + + mInboundQueue.enqueueAtHead(nextEntry); + } } // Dispatch the motion. @@ -1115,7 +1149,8 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0)); + addWindowTargetLocked(mFocusedWindow, + InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0)); // Done. Failed: @@ -1132,7 +1167,8 @@ Unresponsive: } int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, - const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) { + const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions, + const MotionSample** outSplitBatchAfterSample) { enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, INJECTION_PERMISSION_GRANTED, @@ -1175,14 +1211,19 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Update the touch state as needed based on the properties of the touch event. int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING; InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; + const InputWindow* newHoverWindow = NULL; bool isSplit = mTouchState.split; bool wrongDevice = mTouchState.down && (mTouchState.deviceId != entry->deviceId || mTouchState.source != entry->source); - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - || maskedAction == AMOTION_EVENT_ACTION_SCROLL) { + bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE + || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER + || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); + bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN + || maskedAction == AMOTION_EVENT_ACTION_SCROLL + || isHoverAction); + if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; if (wrongDevice && !down) { mTempTouchState.copyFrom(mTouchState); @@ -1198,26 +1239,25 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, mTempTouchState.copyFrom(mTouchState); } if (wrongDevice) { -#if DEBUG_INPUT_DISPATCHER_POLICY +#if DEBUG_FOCUS LOGD("Dropping event because a pointer for a different device is already down."); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) - || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - || maskedAction == AMOTION_EVENT_ACTION_SCROLL) { + if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ + const MotionSample* sample = &entry->firstSample; int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->firstSample.pointerCoords[pointerIndex]. + int32_t x = int32_t(sample->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->firstSample.pointerCoords[pointerIndex]. + int32_t y = int32_t(sample->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_Y)); const InputWindow* newTouchedWindow = NULL; const InputWindow* topErrorWindow = NULL; + bool isTouchModal = false; // Traverse windows from front to back to find touched window and outside targets. size_t numWindows = mWindows.size(); @@ -1233,7 +1273,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (window->visible) { if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE + isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || window->touchableRegionContainsPoint(x, y)) { if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) { @@ -1245,7 +1285,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (maskedAction == AMOTION_EVENT_ACTION_DOWN && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) { - int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE; + int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; if (isWindowObscuredAtPointLocked(window, x, y)) { outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } @@ -1298,7 +1338,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } // Set target flags. - int32_t targetFlags = InputTarget::FLAG_FOREGROUND; + int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS; if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } @@ -1306,6 +1346,28 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } + // Update hover state. + if (isHoverAction) { + newHoverWindow = newTouchedWindow; + + // Ensure all subsequent motion samples are also within the touched window. + // Set *outSplitBatchAfterSample to the sample before the first one that is not + // within the touched window. + if (!isTouchModal) { + while (sample->next) { + if (!newHoverWindow->touchableRegionContainsPoint( + sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), + sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) { + *outSplitBatchAfterSample = sample; + break; + } + sample = sample->next; + } + } + } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { + newHoverWindow = mLastHoverWindow; + } + // Update the temporary touch state. BitSet32 pointerIds; if (isSplit) { @@ -1318,7 +1380,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // If the pointer is not currently down, then ignore the event. if (! mTempTouchState.down) { -#if DEBUG_INPUT_DISPATCHER_POLICY +#if DEBUG_FOCUS LOGD("Dropping event because the pointer is not down or we previously " "dropped the pointer down event."); #endif @@ -1327,6 +1389,29 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } + if (newHoverWindow != mLastHoverWindow) { + // Split the batch here so we send exactly one sample as part of ENTER or EXIT. + *outSplitBatchAfterSample = &entry->firstSample; + + // Let the previous window know that the hover sequence is over. + if (mLastHoverWindow) { +#if DEBUG_HOVER + LOGD("Sending hover exit event to window %s.", mLastHoverWindow->name.string()); +#endif + mTempTouchState.addOrUpdateWindow(mLastHoverWindow, + InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); + } + + // Let the new window know that the hover sequence is starting. + if (newHoverWindow) { +#if DEBUG_HOVER + LOGD("Sending hover enter event to window %s.", newHoverWindow->name.string()); +#endif + mTempTouchState.addOrUpdateWindow(newHoverWindow, + InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); + } + } + // Check permission to inject into all touched foreground windows and ensure there // is at least one touched foreground window. { @@ -1343,7 +1428,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } if (! haveForegroundWindow) { -#if DEBUG_INPUT_DISPATCHER_POLICY +#if DEBUG_FOCUS LOGD("Dropping event because there is no touched foreground window to receive it."); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; @@ -1360,7 +1445,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // If the touched window is paused then keep waiting. if (touchedWindow.window->paused) { -#if DEBUG_INPUT_DISPATCHER_POLICY +#if DEBUG_FOCUS LOGD("Waiting because touched window is paused."); #endif injectionResult = handleTargetsNotReadyLocked(currentTime, entry, @@ -1393,7 +1478,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const InputWindow* window = & mWindows[i]; if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) { mTempTouchState.addOrUpdateWindow(window, - InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0)); + InputTarget::FLAG_WINDOW_IS_OBSCURED + | InputTarget::FLAG_DISPATCH_AS_IS, + BitSet32(0)); } } } @@ -1408,8 +1495,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, touchedWindow.pointerIds); } - // Drop the outside touch window since we will not care about them in the next iteration. - mTempTouchState.removeOutsideTouchWindows(); + // Drop the outside or hover touch windows since we will not care about them + // in the next iteration. + mTempTouchState.filterNonAsIsTouchWindows(); Failed: // Check injection permission once and for all. @@ -1426,7 +1514,7 @@ Failed: if (!wrongDevice) { if (maskedAction == AMOTION_EVENT_ACTION_UP || maskedAction == AMOTION_EVENT_ACTION_CANCEL - || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { + || isHoverAction) { // All pointers up or canceled. mTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { @@ -1463,6 +1551,9 @@ Failed: // Save changes to touch state as-is for all other actions. mTouchState.copyFrom(mTempTouchState); } + + // Update hover state. + mLastHoverWindow = newHoverWindow; } } else { #if DEBUG_FOCUS @@ -1728,10 +1819,36 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, } } + // Enqueue dispatch entries for the requested modes. + enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, + resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); + enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, + resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_OUTSIDE); + enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, + resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); + enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, + resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_IS); + + // If the outbound queue was previously empty, start the dispatch cycle going. + if (wasEmpty) { + activateConnectionLocked(connection.get()); + startDispatchCycleLocked(currentTime, connection); + } +} + +void InputDispatcher::enqueueDispatchEntryLocked( + const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, + bool resumeWithAppendedMotionSample, int32_t dispatchMode) { + int32_t inputTargetFlags = inputTarget->flags; + if (!(inputTargetFlags & dispatchMode)) { + return; + } + inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode; + // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref - inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset); + inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset); if (dispatchEntry->hasForegroundTarget()) { incrementPendingForegroundDispatchesLocked(eventEntry); } @@ -1752,12 +1869,6 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, // Enqueue the dispatch entry. connection->outboundQueue.enqueueAtTail(dispatchEntry); - - // If the outbound queue was previously empty, start the dispatch cycle going. - if (wasEmpty) { - activateConnectionLocked(connection.get()); - startDispatchCycleLocked(currentTime, connection); - } } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, @@ -1776,12 +1887,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, // Mark the dispatch entry as in progress. dispatchEntry->inProgress = true; - // Update the connection's input state. - EventEntry* eventEntry = dispatchEntry->eventEntry; - connection->inputState.trackEvent(eventEntry); - // Publish the event. status_t status; + EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); @@ -1790,6 +1898,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, int32_t action = keyEntry->action; int32_t flags = keyEntry->flags; + // Update the connection's input state. + connection->inputState.trackKey(keyEntry, action); + // Publish the key event. status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->source, action, flags, keyEntry->keyCode, keyEntry->scanCode, @@ -1811,8 +1922,12 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, // Apply target flags. int32_t action = motionEntry->action; int32_t flags = motionEntry->flags; - if (dispatchEntry->targetFlags & InputTarget::FLAG_OUTSIDE) { + if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { action = AMOTION_EVENT_ACTION_OUTSIDE; + } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { + action = AMOTION_EVENT_ACTION_HOVER_EXIT; + } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { + action = AMOTION_EVENT_ACTION_HOVER_ENTER; } if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { flags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; @@ -1837,6 +1952,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, yOffset = 0.0f; } + // Update the connection's input state. + connection->inputState.trackMotion(motionEntry, action); + // Publish the motion event and the first motion sample. status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId, motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState, @@ -1853,31 +1971,34 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, return; } - // Append additional motion samples. - MotionSample* nextMotionSample = firstMotionSample->next; - for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) { - status = connection->inputPublisher.appendMotionSample( - nextMotionSample->eventTime, nextMotionSample->pointerCoords); - if (status == NO_MEMORY) { + if (action == AMOTION_EVENT_ACTION_MOVE + || action == AMOTION_EVENT_ACTION_HOVER_MOVE) { + // Append additional motion samples. + MotionSample* nextMotionSample = firstMotionSample->next; + for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) { + status = connection->inputPublisher.appendMotionSample( + nextMotionSample->eventTime, nextMotionSample->pointerCoords); + if (status == NO_MEMORY) { #if DEBUG_DISPATCH_CYCLE LOGD("channel '%s' ~ Shared memory buffer full. Some motion samples will " "be sent in the next dispatch cycle.", connection->getInputChannelName()); #endif - break; - } - if (status != OK) { - LOGE("channel '%s' ~ Could not append motion sample " - "for a reason other than out of memory, status=%d", - connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection); - return; + break; + } + if (status != OK) { + LOGE("channel '%s' ~ Could not append motion sample " + "for a reason other than out of memory, status=%d", + connection->getInputChannelName(), status); + abortBrokenDispatchCycleLocked(currentTime, connection); + return; + } } - } - // Remember the next motion sample that we could not dispatch, in case we ran out - // of space in the shared memory buffer. - dispatchEntry->tailMotionSample = nextMotionSample; + // Remember the next motion sample that we could not dispatch, in case we ran out + // of space in the shared memory buffer. + dispatchEntry->tailMotionSample = nextMotionSample; + } break; } @@ -2135,8 +2256,8 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet if (pointerIds.hasBit(pointerId)) { splitPointerIndexMap[splitPointerCount] = originalPointerIndex; splitPointerIds[splitPointerCount] = pointerId; - splitPointerCoords[splitPointerCount] = - originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]; + splitPointerCoords[splitPointerCount].copyFrom( + originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]); splitPointerCount += 1; } } @@ -2199,14 +2320,19 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount; splitPointerIndex++) { uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex]; - splitPointerCoords[splitPointerIndex] = - originalMotionSample->pointerCoords[originalPointerIndex]; + splitPointerCoords[splitPointerIndex].copyFrom( + originalMotionSample->pointerCoords[originalPointerIndex]); } mAllocator.appendMotionSample(splitMotionEntry, originalMotionSample->eventTime, splitPointerCoords); } + if (originalMotionEntry->injectionState) { + splitMotionEntry->injectionState = originalMotionEntry->injectionState; + splitMotionEntry->injectionState->refCount += 1; + } + return splitMotionEntry; } @@ -2416,6 +2542,29 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t continue; } + if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) { + if (!mLastHoverWindow) { +#if DEBUG_BATCHING + LOGD("Not streaming hover move because there is no " + "last hovered window."); +#endif + goto NoBatchingOrStreaming; + } + + const InputWindow* hoverWindow = findTouchedWindowAtLocked( + pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), + pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); + if (mLastHoverWindow != hoverWindow) { +#if DEBUG_BATCHING + LOGD("Not streaming hover move because the last hovered window " + "is '%s' but the currently hovered window is '%s'.", + mLastHoverWindow->name.string(), + hoverWindow ? hoverWindow->name.string() : "<null>"); +#endif + goto NoBatchingOrStreaming; + } + } + // Hurray! This foreground target is currently dispatching a move event // that we can stream onto. Append the motion sample and resume dispatch. mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords); @@ -2694,6 +2843,11 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) { oldFocusedWindowChannel = mFocusedWindow->inputChannel; mFocusedWindow = NULL; } + sp<InputChannel> oldLastHoverWindowChannel; + if (mLastHoverWindow) { + oldLastHoverWindowChannel = mLastHoverWindow->inputChannel; + mLastHoverWindow = NULL; + } mWindows.clear(); @@ -2744,6 +2898,12 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) { } } + // Recover the last hovered window. + if (oldLastHoverWindowChannel != NULL) { + mLastHoverWindow = getWindowLocked(oldLastHoverWindowChannel); + oldLastHoverWindowChannel.clear(); + } + #if DEBUG_FOCUS //logDispatchStateLocked(); #endif @@ -2853,7 +3013,8 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, mTouchState.windows.removeAt(i); int32_t newTargetFlags = oldTargetFlags - & (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT); + & (InputTarget::FLAG_FOREGROUND + | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds); found = true; @@ -3453,7 +3614,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec entry->lastSample = & entry->firstSample; for (uint32_t i = 0; i < pointerCount; i++) { entry->pointerIds[i] = pointerIds[i]; - entry->firstSample.pointerCoords[i] = pointerCoords[i]; + entry->firstSample.pointerCoords[i].copyFrom(pointerCoords[i]); } return entry; } @@ -3541,6 +3702,10 @@ void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) { } } +void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) { + mMotionSamplePool.free(sample); +} + void InputDispatcher::Allocator::releaseDispatchEntry(DispatchEntry* entry) { releaseEventEntry(entry->eventEntry); mDispatchEntryPool.free(entry); @@ -3556,7 +3721,7 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, sample->eventTime = eventTime; uint32_t pointerCount = motionEntry->pointerCount; for (uint32_t i = 0; i < pointerCount; i++) { - sample->pointerCoords[i] = pointerCoords[i]; + sample->pointerCoords[i].copyFrom(pointerCoords[i]); } sample->next = NULL; @@ -3596,22 +3761,19 @@ bool InputDispatcher::InputState::isNeutral() const { return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); } -void InputDispatcher::InputState::trackEvent( - const EventEntry* entry) { +void InputDispatcher::InputState::trackEvent(const EventEntry* entry, int32_t action) { switch (entry->type) { case EventEntry::TYPE_KEY: - trackKey(static_cast<const KeyEntry*>(entry)); + trackKey(static_cast<const KeyEntry*>(entry), action); break; case EventEntry::TYPE_MOTION: - trackMotion(static_cast<const MotionEntry*>(entry)); + trackMotion(static_cast<const MotionEntry*>(entry), action); break; } } -void InputDispatcher::InputState::trackKey( - const KeyEntry* entry) { - int32_t action = entry->action; +void InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action) { for (size_t i = 0; i < mKeyMementos.size(); i++) { KeyMemento& memento = mKeyMementos.editItemAt(i); if (memento.deviceId == entry->deviceId @@ -3646,17 +3808,18 @@ Found: } } -void InputDispatcher::InputState::trackMotion( - const MotionEntry* entry) { - int32_t action = entry->action & AMOTION_EVENT_ACTION_MASK; +void InputDispatcher::InputState::trackMotion(const MotionEntry* entry, int32_t action) { + int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; for (size_t i = 0; i < mMotionMementos.size(); i++) { MotionMemento& memento = mMotionMementos.editItemAt(i); if (memento.deviceId == entry->deviceId && memento.source == entry->source) { - switch (action) { + switch (actionMasked) { case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_HOVER_ENTER: case AMOTION_EVENT_ACTION_HOVER_MOVE: + case AMOTION_EVENT_ACTION_HOVER_EXIT: mMotionMementos.removeAt(i); return; @@ -3677,7 +3840,11 @@ void InputDispatcher::InputState::trackMotion( } Found: - if (action == AMOTION_EVENT_ACTION_DOWN) { + switch (actionMasked) { + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_HOVER_ENTER: + case AMOTION_EVENT_ACTION_HOVER_MOVE: + case AMOTION_EVENT_ACTION_HOVER_EXIT: mMotionMementos.push(); MotionMemento& memento = mMotionMementos.editTop(); memento.deviceId = entry->deviceId; @@ -3686,6 +3853,7 @@ Found: memento.yPrecision = entry->yPrecision; memento.downTime = entry->downTime; memento.setPointers(entry); + memento.hovering = actionMasked != AMOTION_EVENT_ACTION_DOWN; } } @@ -3693,7 +3861,7 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* pointerCount = entry->pointerCount; for (uint32_t i = 0; i < entry->pointerCount; i++) { pointerIds[i] = entry->pointerIds[i]; - pointerCoords[i] = entry->lastSample->pointerCoords[i]; + pointerCoords[i].copyFrom(entry->lastSample->pointerCoords[i]); } } @@ -3718,7 +3886,10 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim if (shouldCancelMotion(memento, options)) { outEvents.push(allocator->obtainMotionEntry(currentTime, memento.deviceId, memento.source, 0, - AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0, + memento.hovering + ? AMOTION_EVENT_ACTION_HOVER_EXIT + : AMOTION_EVENT_ACTION_CANCEL, + 0, 0, 0, memento.xPrecision, memento.yPrecision, memento.downTime, memento.pointerCount, memento.pointerIds, memento.pointerCoords)); mMotionMementos.removeAt(i); @@ -3884,12 +4055,15 @@ void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window, touchedWindow.channel = window->inputChannel; } -void InputDispatcher::TouchState::removeOutsideTouchWindows() { +void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { for (size_t i = 0 ; i < windows.size(); ) { - if (windows[i].targetFlags & InputTarget::FLAG_OUTSIDE) { - windows.removeAt(i); - } else { + TouchedWindow& window = windows.editItemAt(i); + if (window.targetFlags & InputTarget::FLAG_DISPATCH_AS_IS) { + window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; + window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; i += 1; + } else { + windows.removeAt(i); } } } diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 1e118c4..59c5298 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -86,20 +86,40 @@ enum { struct InputTarget { enum { /* This flag indicates that the event is being delivered to a foreground application. */ - FLAG_FOREGROUND = 0x01, - - /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside - * of the area of this target and so should instead be delivered as an - * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ - FLAG_OUTSIDE = 0x02, + FLAG_FOREGROUND = 1 << 0, /* This flag indicates that the target of a MotionEvent is partly or wholly * obscured by another visible window above it. The motion event should be * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ - FLAG_WINDOW_IS_OBSCURED = 0x04, + FLAG_WINDOW_IS_OBSCURED = 1 << 1, /* This flag indicates that a motion event is being split across multiple windows. */ - FLAG_SPLIT = 0x08, + FLAG_SPLIT = 1 << 2, + + /* This flag indicates that the event should be sent as is. + * Should always be set unless the event is to be transmuted. */ + FLAG_DISPATCH_AS_IS = 1 << 8, + + /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside + * of the area of this target and so should instead be delivered as an + * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ + FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, + + /* This flag indicates that a hover sequence is starting in the given window. + * The event is transmuted into ACTION_HOVER_ENTER. */ + FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, + + /* This flag indicates that a hover event happened outside of a window which handled + * previous hover events, signifying the end of the current hover sequence for that + * window. + * The event is transmuted into ACTION_HOVER_ENTER. */ + FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, + + /* Mask for all dispatch modes. */ + FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS + | FLAG_DISPATCH_AS_OUTSIDE + | FLAG_DISPATCH_AS_HOVER_ENTER + | FLAG_DISPATCH_AS_HOVER_EXIT, }; // The input channel to be targeted. @@ -567,6 +587,7 @@ private: void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry); void releaseKeyEntry(KeyEntry* entry); void releaseMotionEntry(MotionEntry* entry); + void freeMotionSample(MotionSample* sample); void releaseDispatchEntry(DispatchEntry* entry); void releaseCommandEntry(CommandEntry* entry); @@ -608,13 +629,13 @@ private: bool isNeutral() const; // Records tracking information for an event that has just been published. - void trackEvent(const EventEntry* entry); + void trackEvent(const EventEntry* entry, int32_t action); // Records tracking information for a key event that has just been published. - void trackKey(const KeyEntry* entry); + void trackKey(const KeyEntry* entry, int32_t action); // Records tracking information for a motion event that has just been published. - void trackMotion(const MotionEntry* entry); + void trackMotion(const MotionEntry* entry, int32_t action); // Synthesizes cancelation events for the current state and resets the tracked state. void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator, @@ -645,6 +666,7 @@ private: uint32_t pointerCount; int32_t pointerIds[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; + bool hovering; void setPointers(const MotionEntry* entry); }; @@ -839,7 +861,7 @@ private: void reset(); void copyFrom(const TouchState& other); void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds); - void removeOutsideTouchWindows(); + void filterNonAsIsTouchWindows(); const InputWindow* getFirstForegroundWindow(); }; @@ -882,6 +904,9 @@ private: bool mInputTargetWaitTimeoutExpired; sp<InputApplicationHandle> mInputTargetWaitApplication; + // Contains the last window which received a hover event. + const InputWindow* mLastHoverWindow; + // Finding targets for input events. void resetTargetsLocked(); void commitTargetsLocked(); @@ -896,7 +921,8 @@ private: int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, nsecs_t* nextWakeupTime); int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, - nsecs_t* nextWakeupTime, bool* outConflictingPointerActions); + nsecs_t* nextWakeupTime, bool* outConflictingPointerActions, + const MotionSample** outSplitBatchAfterSample); void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds); @@ -915,6 +941,9 @@ private: void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, bool resumeWithAppendedMotionSample); + void enqueueDispatchEntryLocked(const sp<Connection>& connection, + EventEntry* eventEntry, const InputTarget* inputTarget, + bool resumeWithAppendedMotionSample, int32_t dispatchMode); void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, bool handled); diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 3029028..82cf62f 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -33,6 +33,9 @@ // Log debug messages about pointer assignment calculations. #define DEBUG_POINTER_ASSIGNMENT 0 +// Log debug messages about gesture detection. +#define DEBUG_GESTURES 0 + #include "InputReader.h" @@ -54,6 +57,38 @@ namespace android { +// --- Constants --- + +// Quiet time between certain gesture transitions. +// Time to allow for all fingers or buttons to settle into a stable state before +// starting a new gesture. +static const nsecs_t QUIET_INTERVAL = 100 * 1000000; // 100 ms + +// The minimum speed that a pointer must travel for us to consider switching the active +// touch pointer to it during a drag. This threshold is set to avoid switching due +// to noise from a finger resting on the touch pad (perhaps just pressing it down). +static const float DRAG_MIN_SWITCH_SPEED = 50.0f; // pixels per second + +// Tap gesture delay time. +// The time between down and up must be less than this to be considered a tap. +static const nsecs_t TAP_INTERVAL = 100 * 1000000; // 100 ms + +// The distance in pixels that the pointer is allowed to move from initial down +// to up and still be called a tap. +static const float TAP_SLOP = 5.0f; // 5 pixels + +// The transition from INDETERMINATE_MULTITOUCH to SWIPE or FREEFORM gesture mode is made when +// all of the pointers have traveled this number of pixels from the start point. +static const float MULTITOUCH_MIN_TRAVEL = 5.0f; + +// The transition from INDETERMINATE_MULTITOUCH to SWIPE gesture mode can only occur when the +// cosine of the angle between the two vectors is greater than or equal to than this value +// which indicates that the vectors are oriented in the same direction. +// When the vectors are oriented in the exactly same direction, the cosine is 1.0. +// (In exactly opposite directions, the cosine is -1.0.) +static const float SWIPE_TRANSITION_ANGLE_COSINE = 0.5f; // cosine of 45 degrees + + // --- Static Functions --- template<typename T> @@ -81,6 +116,12 @@ inline static float pythag(float x, float y) { return sqrtf(x * x + y * y); } +inline static int32_t distanceSquared(int32_t x1, int32_t y1, int32_t x2, int32_t y2) { + int32_t dx = x1 - x2; + int32_t dy = y1 - y2; + return dx * dx + dy * dy; +} + inline static int32_t signExtendNybble(int32_t value) { return value >= 8 ? value - 16 : value; } @@ -190,7 +231,7 @@ InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputDispatcherInterface>& dispatcher) : mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher), - mGlobalMetaState(0), mDisableVirtualKeysTimeout(-1) { + mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX) { configureExcludedDevices(); updateGlobalMetaState(); updateInputConfiguration(); @@ -203,35 +244,61 @@ InputReader::~InputReader() { } void InputReader::loopOnce() { - RawEvent rawEvent; - mEventHub->getEvent(& rawEvent); + int32_t timeoutMillis = -1; + if (mNextTimeout != LLONG_MAX) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); + } + size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); + if (count) { + processEvents(mEventBuffer, count); + } + if (!count || timeoutMillis == 0) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); #if DEBUG_RAW_EVENTS - LOGD("Input event: device=%d type=0x%x scancode=%d keycode=%d value=%d", - rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode, - rawEvent.value); + LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); #endif - - process(& rawEvent); + mNextTimeout = LLONG_MAX; + timeoutExpired(now); + } } -void InputReader::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EventHubInterface::DEVICE_ADDED: - addDevice(rawEvent->deviceId); - break; - - case EventHubInterface::DEVICE_REMOVED: - removeDevice(rawEvent->deviceId); - break; - - case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChanged(rawEvent->when); - break; - - default: - consumeEvent(rawEvent); - break; +void InputReader::processEvents(const RawEvent* rawEvents, size_t count) { + for (const RawEvent* rawEvent = rawEvents; count;) { + int32_t type = rawEvent->type; + size_t batchSize = 1; + if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { + int32_t deviceId = rawEvent->deviceId; + while (batchSize < count) { + if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT + || rawEvent[batchSize].deviceId != deviceId) { + break; + } + batchSize += 1; + } +#if DEBUG_RAW_EVENTS + LOGD("BatchSize: %d Count: %d", batchSize, count); +#endif + processEventsForDevice(deviceId, rawEvent, batchSize); + } else { + switch (rawEvent->type) { + case EventHubInterface::DEVICE_ADDED: + addDevice(rawEvent->deviceId); + break; + case EventHubInterface::DEVICE_REMOVED: + removeDevice(rawEvent->deviceId); + break; + case EventHubInterface::FINISHED_DEVICE_SCAN: + handleConfigurationChanged(rawEvent->when); + break; + default: + assert(false); // can't happen + break; + } + } + count -= batchSize; + rawEvent += batchSize; } } @@ -352,9 +419,8 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui return device; } -void InputReader::consumeEvent(const RawEvent* rawEvent) { - int32_t deviceId = rawEvent->deviceId; - +void InputReader::processEventsForDevice(int32_t deviceId, + const RawEvent* rawEvents, size_t count) { { // acquire device registry reader lock RWLock::AutoRLock _rl(mDeviceRegistryLock); @@ -370,7 +436,20 @@ void InputReader::consumeEvent(const RawEvent* rawEvent) { return; } - device->process(rawEvent); + device->process(rawEvents, count); + } // release device registry reader lock +} + +void InputReader::timeoutExpired(nsecs_t when) { + { // acquire device registry reader lock + RWLock::AutoRLock _rl(mDeviceRegistryLock); + + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (!device->isIgnored()) { + device->timeoutExpired(when); + } + } } // release device registry reader lock } @@ -484,6 +563,12 @@ void InputReader::fadePointer() { } // release device registry reader lock } +void InputReader::requestTimeoutAtTime(nsecs_t when) { + if (when < mNextTimeout) { + mNextTimeout = when; + } +} + void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) { { // acquire state lock AutoMutex _l(mStateLock); @@ -713,11 +798,33 @@ void InputDevice::reset() { } } -void InputDevice::process(const RawEvent* rawEvent) { +void InputDevice::process(const RawEvent* rawEvents, size_t count) { + // Process all of the events in order for each mapper. + // We cannot simply ask each mapper to process them in bulk because mappers may + // have side-effects that must be interleaved. For example, joystick movement events and + // gamepad button presses are handled by different mappers but they should be dispatched + // in the order received. + size_t numMappers = mMappers.size(); + for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { +#if DEBUG_RAW_EVENTS + LOGD("Input event: device=%d type=0x%04x scancode=0x%04x " + "keycode=0x%04x value=0x%04x flags=0x%08x", + rawEvent->deviceId, rawEvent->type, rawEvent->scanCode, rawEvent->keyCode, + rawEvent->value, rawEvent->flags); +#endif + + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->process(rawEvent); + } + } +} + +void InputDevice::timeoutExpired(nsecs_t when) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; - mapper->process(rawEvent); + mapper->timeoutExpired(when); } } @@ -812,6 +919,9 @@ void InputMapper::configure() { void InputMapper::reset() { } +void InputMapper::timeoutExpired(nsecs_t when) { +} + int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { return AKEY_STATE_UNKNOWN; } @@ -1495,8 +1605,15 @@ void CursorInputMapper::sync(nsecs_t when) { motionEventAction, 0, metaState, motionEventEdgeFlags, 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); - mAccumulator.clear(); + // Send hover move after UP to tell the application that the mouse is hovering now. + if (motionEventAction == AMOTION_EVENT_ACTION_UP + && mPointerController != NULL) { + getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); + } + // Send scroll events. if (vscroll != 0 || hscroll != 0) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); @@ -1505,6 +1622,8 @@ void CursorInputMapper::sync(nsecs_t when) { AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); } + + mAccumulator.clear(); } int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { @@ -1540,7 +1659,7 @@ TouchInputMapper::~TouchInputMapper() { } uint32_t TouchInputMapper::getSources() { - return mTouchSource; + return mTouchSource | mPointerSource; } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { @@ -1579,6 +1698,18 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { if (mLocked.orientedRanges.haveOrientation) { info->addMotionRange(mLocked.orientedRanges.orientation); } + + if (mPointerController != NULL) { + float minX, minY, maxX, maxY; + if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { + info->addMotionRange(AMOTION_EVENT_AXIS_X, mPointerSource, + minX, maxX, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, mPointerSource, + minY, maxY, 0.0f, 0.0f); + } + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mPointerSource, + 0.0f, 1.0f, 0.0f, 0.0f); + } } // release lock } @@ -1608,6 +1739,21 @@ void TouchInputMapper::dump(String8& dump) { dump.appendFormat(INDENT3 "Last Touch:\n"); dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount); + dump.appendFormat(INDENT4 "Button State: 0x%08x\n", mLastTouch.buttonState); + + if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { + dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); + dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", + mLocked.pointerGestureXMovementScale); + dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n", + mLocked.pointerGestureYMovementScale); + dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n", + mLocked.pointerGestureXZoomScale); + dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n", + mLocked.pointerGestureYZoomScale); + dump.appendFormat(INDENT4 "MaxSwipeWidthSquared: %d\n", + mLocked.pointerGestureMaxSwipeWidthSquared); + } } // release lock } @@ -1630,6 +1776,8 @@ void TouchInputMapper::initializeLocked() { mLocked.orientedRanges.haveTouchSize = false; mLocked.orientedRanges.haveToolSize = false; mLocked.orientedRanges.haveOrientation = false; + + mPointerGesture.reset(); } void TouchInputMapper::configure() { @@ -1642,9 +1790,15 @@ void TouchInputMapper::configure() { switch (mParameters.deviceType) { case Parameters::DEVICE_TYPE_TOUCH_SCREEN: mTouchSource = AINPUT_SOURCE_TOUCHSCREEN; + mPointerSource = 0; break; case Parameters::DEVICE_TYPE_TOUCH_PAD: mTouchSource = AINPUT_SOURCE_TOUCHPAD; + mPointerSource = 0; + break; + case Parameters::DEVICE_TYPE_POINTER: + mTouchSource = AINPUT_SOURCE_TOUCHPAD; + mPointerSource = AINPUT_SOURCE_MOUSE; break; default: assert(false); @@ -1671,14 +1825,26 @@ void TouchInputMapper::configureParameters() { mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime(); + if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) + || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { + // The device is a cursor device with a touch pad attached. + // By default don't use the touch pad to move the pointer. + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else { + // The device is just a touch pad. + // By default use the touch pad to move the pointer and to perform related gestures. + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; + } + String8 deviceTypeString; - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), deviceTypeString)) { if (deviceTypeString == "touchScreen") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; } else if (deviceTypeString == "touchPad") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else if (deviceTypeString == "pointer") { + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } else { LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); } @@ -1690,6 +1856,7 @@ void TouchInputMapper::configureParameters() { mParameters.associatedDisplayId = mParameters.orientationAware || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN + || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER ? 0 : -1; } @@ -1703,6 +1870,9 @@ void TouchInputMapper::dumpParameters(String8& dump) { case Parameters::DEVICE_TYPE_TOUCH_PAD: dump.append(INDENT4 "DeviceType: touchPad\n"); break; + case Parameters::DEVICE_TYPE_POINTER: + dump.append(INDENT4 "DeviceType: pointer\n"); + break; default: assert(false); } @@ -1776,6 +1946,11 @@ bool TouchInputMapper::configureSurfaceLocked() { } } + if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER + && mPointerController == NULL) { + mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + } + bool orientationChanged = mLocked.surfaceOrientation != orientation; if (orientationChanged) { mLocked.surfaceOrientation = orientation; @@ -1997,6 +2172,37 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.orientedRanges.y.fuzz = mLocked.yScale; break; } + + // Compute pointer gesture detection parameters. + // TODO: These factors should not be hardcoded. + if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { + int32_t rawWidth = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1; + int32_t rawHeight = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1; + + // Scale movements such that one whole swipe of the touch pad covers a portion + // of the display along whichever axis of the touch pad is longer. + // Assume that the touch pad has a square aspect ratio such that movements in + // X and Y of the same number of raw units cover the same physical distance. + const float scaleFactor = 0.8f; + + mLocked.pointerGestureXMovementScale = rawWidth > rawHeight + ? scaleFactor * float(mLocked.associatedDisplayWidth) / rawWidth + : scaleFactor * float(mLocked.associatedDisplayHeight) / rawHeight; + mLocked.pointerGestureYMovementScale = mLocked.pointerGestureXMovementScale; + + // Scale zooms to cover a smaller range of the display than movements do. + // This value determines the area around the pointer that is affected by freeform + // pointer gestures. + mLocked.pointerGestureXZoomScale = mLocked.pointerGestureXMovementScale * 0.4f; + mLocked.pointerGestureYZoomScale = mLocked.pointerGestureYMovementScale * 0.4f; + + // Max width between pointers to detect a swipe gesture is 3/4 of the short + // axis of the touch pad. Touches that are wider than this are translated + // into freeform gestures. + mLocked.pointerGestureMaxSwipeWidthSquared = min(rawWidth, rawHeight) * 3 / 4; + mLocked.pointerGestureMaxSwipeWidthSquared *= + mLocked.pointerGestureMaxSwipeWidthSquared; + } } return true; @@ -2428,6 +2634,19 @@ void TouchInputMapper::reset() { } void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { +#if DEBUG_RAW_EVENTS + if (!havePointerIds) { + LOGD("syncTouch: pointerCount=%d, no pointer ids", mCurrentTouch.pointerCount); + } else { + LOGD("syncTouch: pointerCount=%d, up=0x%08x, down=0x%08x, move=0x%08x, " + "last=0x%08x, current=0x%08x", mCurrentTouch.pointerCount, + mLastTouch.idBits.value & ~mCurrentTouch.idBits.value, + mCurrentTouch.idBits.value & ~mLastTouch.idBits.value, + mLastTouch.idBits.value & mCurrentTouch.idBits.value, + mLastTouch.idBits.value, mCurrentTouch.idBits.value); + } +#endif + // Preprocess pointer data. if (mParameters.useBadTouchFilter) { if (applyBadTouchFilter()) { @@ -2441,7 +2660,7 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { } } - if (! havePointerIds) { + if (!havePointerIds) { calculatePointerIds(); } @@ -2476,12 +2695,17 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { TouchResult touchResult = consumeOffScreenTouches(when, policyFlags); if (touchResult == DISPATCH_TOUCH) { suppressSwipeOntoVirtualKeys(when); + if (mPointerController != NULL) { + dispatchPointerGestures(when, policyFlags); + } dispatchTouches(when, policyFlags); } // Copy current touch to last touch in preparation for the next cycle. + // Keep the button state so we can track edge-triggered button state changes. if (touchResult == DROP_STROKE) { mLastTouch.clear(); + mLastTouch.buttonState = savedTouch->buttonState; } else { mLastTouch.copyFrom(*savedTouch); } @@ -2629,329 +2853,1097 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { return; // nothing to do! } + // Update current touch coordinates. + int32_t edgeFlags; + float xPrecision, yPrecision; + prepareTouches(&edgeFlags, &xPrecision, &yPrecision); + + // Dispatch motions. BitSet32 currentIdBits = mCurrentTouch.idBits; BitSet32 lastIdBits = mLastTouch.idBits; + uint32_t metaState = getContext()->getGlobalMetaState(); if (currentIdBits == lastIdBits) { // No pointer id changes so this is a move event. // The dispatcher takes care of batching moves so we don't have to deal with that here. - int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE; - dispatchTouch(when, policyFlags, & mCurrentTouch, - currentIdBits, -1, currentPointerCount, motionEventAction); + dispatchMotion(when, policyFlags, mTouchSource, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + mCurrentTouchCoords, mCurrentTouch.idToIndex, currentIdBits, -1, + xPrecision, yPrecision, mDownTime); } else { // There may be pointers going up and pointers going down and pointers moving // all at the same time. - BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value); - BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value); - BitSet32 activeIdBits(lastIdBits.value); - uint32_t pointerCount = lastPointerCount; - - // Produce an intermediate representation of the touch data that consists of the - // old location of pointers that have just gone up and the new location of pointers that - // have just moved but omits the location of pointers that have just gone down. - TouchData interimTouch; - interimTouch.copyFrom(mLastTouch); - + BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); + BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); - bool moveNeeded = false; - while (!moveIdBits.isEmpty()) { - uint32_t moveId = moveIdBits.firstMarkedBit(); - moveIdBits.clearBit(moveId); - - int32_t oldIndex = mLastTouch.idToIndex[moveId]; - int32_t newIndex = mCurrentTouch.idToIndex[moveId]; - if (mLastTouch.pointers[oldIndex] != mCurrentTouch.pointers[newIndex]) { - interimTouch.pointers[oldIndex] = mCurrentTouch.pointers[newIndex]; - moveNeeded = true; - } - } + BitSet32 dispatchedIdBits(lastIdBits.value); + + // Update last coordinates of pointers that have moved so that we observe the new + // pointer positions at the same time as other pointers that have just gone up. + bool moveNeeded = updateMovedPointerCoords( + mCurrentTouchCoords, mCurrentTouch.idToIndex, + mLastTouchCoords, mLastTouch.idToIndex, + moveIdBits); - // Dispatch pointer up events using the interim pointer locations. + // Dispatch pointer up events. while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.firstMarkedBit(); upIdBits.clearBit(upId); - BitSet32 oldActiveIdBits = activeIdBits; - activeIdBits.clearBit(upId); - int32_t motionEventAction; - if (activeIdBits.isEmpty()) { - motionEventAction = AMOTION_EVENT_ACTION_UP; - } else { - motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP; - } - - dispatchTouch(when, policyFlags, &interimTouch, - oldActiveIdBits, upId, pointerCount, motionEventAction); - pointerCount -= 1; + dispatchMotion(when, policyFlags, mTouchSource, + AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, 0, + mLastTouchCoords, mLastTouch.idToIndex, dispatchedIdBits, upId, + xPrecision, yPrecision, mDownTime); + dispatchedIdBits.clearBit(upId); } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. if (moveNeeded) { - dispatchTouch(when, policyFlags, &mCurrentTouch, - activeIdBits, -1, pointerCount, AMOTION_EVENT_ACTION_MOVE); + assert(moveIdBits.value == dispatchedIdBits.value); + dispatchMotion(when, policyFlags, mTouchSource, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, 0, + mCurrentTouchCoords, mCurrentTouch.idToIndex, dispatchedIdBits, -1, + xPrecision, yPrecision, mDownTime); } // Dispatch pointer down events using the new pointer locations. while (!downIdBits.isEmpty()) { uint32_t downId = downIdBits.firstMarkedBit(); downIdBits.clearBit(downId); - BitSet32 oldActiveIdBits = activeIdBits; - activeIdBits.markBit(downId); + dispatchedIdBits.markBit(downId); - int32_t motionEventAction; - if (oldActiveIdBits.isEmpty()) { - motionEventAction = AMOTION_EVENT_ACTION_DOWN; + if (dispatchedIdBits.count() == 1) { + // First pointer is going down. Set down time. mDownTime = when; } else { - motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN; + // Only send edge flags with first pointer down. + edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; } - pointerCount += 1; - dispatchTouch(when, policyFlags, &mCurrentTouch, - activeIdBits, downId, pointerCount, motionEventAction); + dispatchMotion(when, policyFlags, mTouchSource, + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, edgeFlags, + mCurrentTouchCoords, mCurrentTouch.idToIndex, dispatchedIdBits, downId, + xPrecision, yPrecision, mDownTime); } } -} -void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, - TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, - int32_t motionEventAction) { - int32_t pointerIds[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - int32_t motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; - float xPrecision, yPrecision; + // Update state for next time. + for (uint32_t i = 0; i < currentPointerCount; i++) { + mLastTouchCoords[i].copyFrom(mCurrentTouchCoords[i]); + } +} - { // acquire lock - AutoMutex _l(mLock); +void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags, + float* outXPrecision, float* outYPrecision) { + uint32_t currentPointerCount = mCurrentTouch.pointerCount; + uint32_t lastPointerCount = mLastTouch.pointerCount; - // Walk through the the active pointers and map touch screen coordinates (TouchData) into - // display or surface coordinates (PointerCoords) and adjust for display orientation. - for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - uint32_t inIndex = touch->idToIndex[id]; + AutoMutex _l(mLock); - const PointerData& in = touch->pointers[inIndex]; + // Walk through the the active pointers and map touch screen coordinates (TouchData) into + // display or surface coordinates (PointerCoords) and adjust for display orientation. + for (uint32_t i = 0; i < currentPointerCount; i++) { + const PointerData& in = mCurrentTouch.pointers[i]; - // ToolMajor and ToolMinor - float toolMajor, toolMinor; - switch (mCalibration.toolSizeCalibration) { - case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC: - toolMajor = in.toolMajor * mLocked.geometricScale; - if (mRawAxes.toolMinor.valid) { - toolMinor = in.toolMinor * mLocked.geometricScale; - } else { - toolMinor = toolMajor; - } - break; - case Calibration::TOOL_SIZE_CALIBRATION_LINEAR: - toolMajor = in.toolMajor != 0 - ? in.toolMajor * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias + // ToolMajor and ToolMinor + float toolMajor, toolMinor; + switch (mCalibration.toolSizeCalibration) { + case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC: + toolMajor = in.toolMajor * mLocked.geometricScale; + if (mRawAxes.toolMinor.valid) { + toolMinor = in.toolMinor * mLocked.geometricScale; + } else { + toolMinor = toolMajor; + } + break; + case Calibration::TOOL_SIZE_CALIBRATION_LINEAR: + toolMajor = in.toolMajor != 0 + ? in.toolMajor * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias + : 0; + if (mRawAxes.toolMinor.valid) { + toolMinor = in.toolMinor != 0 + ? in.toolMinor * mLocked.toolSizeLinearScale + + mLocked.toolSizeLinearBias : 0; - if (mRawAxes.toolMinor.valid) { - toolMinor = in.toolMinor != 0 - ? in.toolMinor * mLocked.toolSizeLinearScale - + mLocked.toolSizeLinearBias - : 0; - } else { - toolMinor = toolMajor; - } - break; - case Calibration::TOOL_SIZE_CALIBRATION_AREA: - if (in.toolMajor != 0) { - float diameter = sqrtf(in.toolMajor - * mLocked.toolSizeAreaScale + mLocked.toolSizeAreaBias); - toolMajor = diameter * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias; - } else { - toolMajor = 0; - } + } else { toolMinor = toolMajor; - break; - default: + } + break; + case Calibration::TOOL_SIZE_CALIBRATION_AREA: + if (in.toolMajor != 0) { + float diameter = sqrtf(in.toolMajor + * mLocked.toolSizeAreaScale + mLocked.toolSizeAreaBias); + toolMajor = diameter * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias; + } else { toolMajor = 0; - toolMinor = 0; - break; } + toolMinor = toolMajor; + break; + default: + toolMajor = 0; + toolMinor = 0; + break; + } + + if (mCalibration.haveToolSizeIsSummed && mCalibration.toolSizeIsSummed) { + toolMajor /= currentPointerCount; + toolMinor /= currentPointerCount; + } - if (mCalibration.haveToolSizeIsSummed && mCalibration.toolSizeIsSummed) { - toolMajor /= pointerCount; - toolMinor /= pointerCount; + // Pressure + float rawPressure; + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + rawPressure = in.pressure; + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + rawPressure = in.touchMajor; + break; + default: + rawPressure = 0; + } + + float pressure; + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + pressure = rawPressure * mLocked.pressureScale; + break; + default: + pressure = 1; + break; + } + + // TouchMajor and TouchMinor + float touchMajor, touchMinor; + switch (mCalibration.touchSizeCalibration) { + case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC: + touchMajor = in.touchMajor * mLocked.geometricScale; + if (mRawAxes.touchMinor.valid) { + touchMinor = in.touchMinor * mLocked.geometricScale; + } else { + touchMinor = touchMajor; } + break; + case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE: + touchMajor = toolMajor * pressure; + touchMinor = toolMinor * pressure; + break; + default: + touchMajor = 0; + touchMinor = 0; + break; + } - // Pressure - float rawPressure; - switch (mCalibration.pressureSource) { - case Calibration::PRESSURE_SOURCE_PRESSURE: - rawPressure = in.pressure; - break; - case Calibration::PRESSURE_SOURCE_TOUCH: - rawPressure = in.touchMajor; - break; - default: - rawPressure = 0; + if (touchMajor > toolMajor) { + touchMajor = toolMajor; + } + if (touchMinor > toolMinor) { + touchMinor = toolMinor; + } + + // Size + float size; + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_NORMALIZED: { + float rawSize = mRawAxes.toolMinor.valid + ? avg(in.toolMajor, in.toolMinor) + : in.toolMajor; + size = rawSize * mLocked.sizeScale; + break; + } + default: + size = 0; + break; + } + + // Orientation + float orientation; + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + orientation = in.orientation * mLocked.orientationScale; + break; + case Calibration::ORIENTATION_CALIBRATION_VECTOR: { + int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); + int32_t c2 = signExtendNybble(in.orientation & 0x0f); + if (c1 != 0 || c2 != 0) { + orientation = atan2f(c1, c2) * 0.5f; + float scale = 1.0f + pythag(c1, c2) / 16.0f; + touchMajor *= scale; + touchMinor /= scale; + toolMajor *= scale; + toolMinor /= scale; + } else { + orientation = 0; } + break; + } + default: + orientation = 0; + } - float pressure; - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - pressure = rawPressure * mLocked.pressureScale; - break; - default: - pressure = 1; - break; + // X and Y + // Adjust coords for surface orientation. + float x, y; + switch (mLocked.surfaceOrientation) { + case DISPLAY_ORIENTATION_90: + x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale; + y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale; + orientation -= M_PI_2; + if (orientation < - M_PI_2) { + orientation += M_PI; + } + break; + case DISPLAY_ORIENTATION_180: + x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale; + y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale; + break; + case DISPLAY_ORIENTATION_270: + x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale; + y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale; + orientation += M_PI_2; + if (orientation > M_PI_2) { + orientation -= M_PI; } + break; + default: + x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale; + y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale; + break; + } - // TouchMajor and TouchMinor - float touchMajor, touchMinor; - switch (mCalibration.touchSizeCalibration) { - case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC: - touchMajor = in.touchMajor * mLocked.geometricScale; - if (mRawAxes.touchMinor.valid) { - touchMinor = in.touchMinor * mLocked.geometricScale; - } else { - touchMinor = touchMajor; - } - break; - case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE: - touchMajor = toolMajor * pressure; - touchMinor = toolMinor * pressure; - break; - default: - touchMajor = 0; - touchMinor = 0; - break; + // Write output coords. + PointerCoords& out = mCurrentTouchCoords[i]; + out.clear(); + out.setAxisValue(AMOTION_EVENT_AXIS_X, x); + out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); + out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); + out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); + out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); + out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); + out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); + } + + // Check edge flags by looking only at the first pointer since the flags are + // global to the event. + *outEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; + if (lastPointerCount == 0 && currentPointerCount > 0) { + const PointerData& in = mCurrentTouch.pointers[0]; + + if (in.x <= mRawAxes.x.minValue) { + *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT, + mLocked.surfaceOrientation); + } else if (in.x >= mRawAxes.x.maxValue) { + *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT, + mLocked.surfaceOrientation); + } + if (in.y <= mRawAxes.y.minValue) { + *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP, + mLocked.surfaceOrientation); + } else if (in.y >= mRawAxes.y.maxValue) { + *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM, + mLocked.surfaceOrientation); + } + } + + *outXPrecision = mLocked.orientedXPrecision; + *outYPrecision = mLocked.orientedYPrecision; +} + +void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags) { + // Update current gesture coordinates. + bool cancelPreviousGesture, finishPreviousGesture; + preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture); + + // Send events! + uint32_t metaState = getContext()->getGlobalMetaState(); + + // Update last coordinates of pointers that have moved so that we observe the new + // pointer positions at the same time as other pointers that have just gone up. + bool down = mPointerGesture.currentGestureMode == PointerGesture::CLICK_OR_DRAG + || mPointerGesture.currentGestureMode == PointerGesture::SWIPE + || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; + bool moveNeeded = false; + if (down && !cancelPreviousGesture && !finishPreviousGesture + && mPointerGesture.lastGesturePointerCount != 0 + && mPointerGesture.currentGesturePointerCount != 0) { + BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value + & mPointerGesture.lastGestureIdBits.value); + moveNeeded = updateMovedPointerCoords( + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, + movedGestureIdBits); + } + + // Send motion events for all pointers that went up or were canceled. + BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); + if (!dispatchedGestureIdBits.isEmpty()) { + if (cancelPreviousGesture) { + dispatchMotion(when, policyFlags, mPointerSource, + AMOTION_EVENT_ACTION_CANCEL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, + dispatchedGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); + + dispatchedGestureIdBits.clear(); + } else { + BitSet32 upGestureIdBits; + if (finishPreviousGesture) { + upGestureIdBits = dispatchedGestureIdBits; + } else { + upGestureIdBits.value = dispatchedGestureIdBits.value + & ~mPointerGesture.currentGestureIdBits.value; } + while (!upGestureIdBits.isEmpty()) { + uint32_t id = upGestureIdBits.firstMarkedBit(); + upGestureIdBits.clearBit(id); + + dispatchMotion(when, policyFlags, mPointerSource, + AMOTION_EVENT_ACTION_POINTER_UP, 0, + metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, + dispatchedGestureIdBits, id, + 0, 0, mPointerGesture.downTime); + + dispatchedGestureIdBits.clearBit(id); + } + } + } + + // Send motion events for all pointers that moved. + if (moveNeeded) { + dispatchMotion(when, policyFlags, mPointerSource, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + dispatchedGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); + } + + // Send motion events for all pointers that went down. + if (down) { + BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value + & ~dispatchedGestureIdBits.value); + while (!downGestureIdBits.isEmpty()) { + uint32_t id = downGestureIdBits.firstMarkedBit(); + downGestureIdBits.clearBit(id); + dispatchedGestureIdBits.markBit(id); + + int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; + if (dispatchedGestureIdBits.count() == 1) { + // First pointer is going down. Calculate edge flags and set down time. + uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + const PointerCoords& downCoords = mPointerGesture.currentGestureCoords[index]; + edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController, + downCoords.getAxisValue(AMOTION_EVENT_AXIS_X), + downCoords.getAxisValue(AMOTION_EVENT_AXIS_Y)); + mPointerGesture.downTime = when; + } + + dispatchMotion(when, policyFlags, mPointerSource, + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, edgeFlags, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + dispatchedGestureIdBits, id, + 0, 0, mPointerGesture.downTime); + } + } - if (touchMajor > toolMajor) { - touchMajor = toolMajor; + // Send down and up for a tap. + if (mPointerGesture.currentGestureMode == PointerGesture::TAP) { + const PointerCoords& coords = mPointerGesture.currentGestureCoords[0]; + int32_t edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController, + coords.getAxisValue(AMOTION_EVENT_AXIS_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_Y)); + nsecs_t downTime = mPointerGesture.downTime = mPointerGesture.tapTime; + mPointerGesture.resetTapTime(); + + dispatchMotion(downTime, policyFlags, mPointerSource, + AMOTION_EVENT_ACTION_DOWN, 0, metaState, edgeFlags, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, -1, + 0, 0, downTime); + dispatchMotion(when, policyFlags, mPointerSource, + AMOTION_EVENT_ACTION_UP, 0, metaState, edgeFlags, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, -1, + 0, 0, downTime); + } + + // Send motion events for hover. + if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { + dispatchMotion(when, policyFlags, mPointerSource, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); + } + + // Update state. + mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; + if (!down) { + mPointerGesture.lastGesturePointerCount = 0; + mPointerGesture.lastGestureIdBits.clear(); + } else { + uint32_t currentGesturePointerCount = mPointerGesture.currentGesturePointerCount; + mPointerGesture.lastGesturePointerCount = currentGesturePointerCount; + mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; + for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + mPointerGesture.lastGestureCoords[index].copyFrom( + mPointerGesture.currentGestureCoords[index]); + mPointerGesture.lastGestureIdToIndex[id] = index; + } + } +} + +void TouchInputMapper::preparePointerGestures(nsecs_t when, + bool* outCancelPreviousGesture, bool* outFinishPreviousGesture) { + *outCancelPreviousGesture = false; + *outFinishPreviousGesture = false; + + AutoMutex _l(mLock); + + // Update the velocity tracker. + { + VelocityTracker::Position positions[MAX_POINTERS]; + uint32_t count = 0; + for (BitSet32 idBits(mCurrentTouch.idBits); !idBits.isEmpty(); count++) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + uint32_t index = mCurrentTouch.idToIndex[id]; + positions[count].x = mCurrentTouch.pointers[index].x + * mLocked.pointerGestureXMovementScale; + positions[count].y = mCurrentTouch.pointers[index].y + * mLocked.pointerGestureYMovementScale; + } + mPointerGesture.velocityTracker.addMovement(when, mCurrentTouch.idBits, positions); + } + + // Pick a new active touch id if needed. + // Choose an arbitrary pointer that just went down, if there is one. + // Otherwise choose an arbitrary remaining pointer. + // This guarantees we always have an active touch id when there is at least one pointer. + // We always switch to the newest pointer down because that's usually where the user's + // attention is focused. + int32_t activeTouchId; + BitSet32 downTouchIdBits(mCurrentTouch.idBits.value & ~mLastTouch.idBits.value); + if (!downTouchIdBits.isEmpty()) { + activeTouchId = mPointerGesture.activeTouchId = downTouchIdBits.firstMarkedBit(); + } else { + activeTouchId = mPointerGesture.activeTouchId; + if (activeTouchId < 0 || !mCurrentTouch.idBits.hasBit(activeTouchId)) { + if (!mCurrentTouch.idBits.isEmpty()) { + activeTouchId = mPointerGesture.activeTouchId = + mCurrentTouch.idBits.firstMarkedBit(); + } else { + activeTouchId = mPointerGesture.activeTouchId = -1; } - if (touchMinor > toolMinor) { - touchMinor = toolMinor; + } + } + + // Update the touch origin data to track where each finger originally went down. + if (mCurrentTouch.pointerCount == 0 || mPointerGesture.touchOrigin.pointerCount == 0) { + // Fast path when all fingers have gone up or down. + mPointerGesture.touchOrigin.copyFrom(mCurrentTouch); + } else { + // Slow path when only some fingers have gone up or down. + for (BitSet32 idBits(mPointerGesture.touchOrigin.idBits.value + & ~mCurrentTouch.idBits.value); !idBits.isEmpty(); ) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + mPointerGesture.touchOrigin.idBits.clearBit(id); + uint32_t index = mPointerGesture.touchOrigin.idToIndex[id]; + uint32_t count = --mPointerGesture.touchOrigin.pointerCount; + while (index < count) { + mPointerGesture.touchOrigin.pointers[index] = + mPointerGesture.touchOrigin.pointers[index + 1]; + uint32_t movedId = mPointerGesture.touchOrigin.pointers[index].id; + mPointerGesture.touchOrigin.idToIndex[movedId] = index; + index += 1; } + } + for (BitSet32 idBits(mCurrentTouch.idBits.value + & ~mPointerGesture.touchOrigin.idBits.value); !idBits.isEmpty(); ) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + mPointerGesture.touchOrigin.idBits.markBit(id); + uint32_t index = mPointerGesture.touchOrigin.pointerCount++; + mPointerGesture.touchOrigin.pointers[index] = + mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]]; + mPointerGesture.touchOrigin.idToIndex[id] = index; + } + } - // Size - float size; - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_NORMALIZED: { - float rawSize = mRawAxes.toolMinor.valid - ? avg(in.toolMajor, in.toolMinor) - : in.toolMajor; - size = rawSize * mLocked.sizeScale; - break; + // Determine whether we are in quiet time. + bool isQuietTime = when < mPointerGesture.quietTime + QUIET_INTERVAL; + if (!isQuietTime) { + if ((mPointerGesture.lastGestureMode == PointerGesture::SWIPE + || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) + && mCurrentTouch.pointerCount < 2) { + // Enter quiet time when exiting swipe or freeform state. + // This is to prevent accidentally entering the hover state and flinging the + // pointer when finishing a swipe and there is still one pointer left onscreen. + isQuietTime = true; + } else if (mPointerGesture.lastGestureMode == PointerGesture::CLICK_OR_DRAG + && mCurrentTouch.pointerCount >= 2 + && !isPointerDown(mCurrentTouch.buttonState)) { + // Enter quiet time when releasing the button and there are still two or more + // fingers down. This may indicate that one finger was used to press the button + // but it has not gone up yet. + isQuietTime = true; + } + if (isQuietTime) { + mPointerGesture.quietTime = when; + } + } + + // Switch states based on button and pointer state. + if (isQuietTime) { + // Case 1: Quiet time. (QUIET) +#if DEBUG_GESTURES + LOGD("Gestures: QUIET for next %0.3fms", + (mPointerGesture.quietTime + QUIET_INTERVAL - when) * 0.000001f); +#endif + *outFinishPreviousGesture = true; + + mPointerGesture.activeGestureId = -1; + mPointerGesture.currentGestureMode = PointerGesture::QUIET; + mPointerGesture.currentGesturePointerCount = 0; + mPointerGesture.currentGestureIdBits.clear(); + } else if (isPointerDown(mCurrentTouch.buttonState)) { + // Case 2: Button is pressed. (DRAG) + // The pointer follows the active touch point. + // Emit DOWN, MOVE, UP events at the pointer location. + // + // Only the active touch matters; other fingers are ignored. This policy helps + // to handle the case where the user places a second finger on the touch pad + // to apply the necessary force to depress an integrated button below the surface. + // We don't want the second finger to be delivered to applications. + // + // For this to work well, we need to make sure to track the pointer that is really + // active. If the user first puts one finger down to click then adds another + // finger to drag then the active pointer should switch to the finger that is + // being dragged. +#if DEBUG_GESTURES + LOGD("Gestures: CLICK_OR_DRAG activeTouchId=%d, " + "currentTouchPointerCount=%d", activeTouchId, mCurrentTouch.pointerCount); +#endif + // Reset state when just starting. + if (mPointerGesture.lastGestureMode != PointerGesture::CLICK_OR_DRAG) { + *outFinishPreviousGesture = true; + mPointerGesture.activeGestureId = 0; + } + + // Switch pointers if needed. + // Find the fastest pointer and follow it. + if (activeTouchId >= 0) { + if (mCurrentTouch.pointerCount > 1) { + int32_t bestId = -1; + float bestSpeed = DRAG_MIN_SWITCH_SPEED; + for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) { + uint32_t id = mCurrentTouch.pointers[i].id; + float vx, vy; + if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { + float speed = pythag(vx, vy); + if (speed > bestSpeed) { + bestId = id; + bestSpeed = speed; + } + } + } + if (bestId >= 0 && bestId != activeTouchId) { + mPointerGesture.activeTouchId = activeTouchId = bestId; +#if DEBUG_GESTURES + LOGD("Gestures: CLICK_OR_DRAG switched pointers, " + "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); +#endif + } } - default: - size = 0; - break; + + if (mLastTouch.idBits.hasBit(activeTouchId)) { + const PointerData& currentPointer = + mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]]; + const PointerData& lastPointer = + mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]]; + float deltaX = (currentPointer.x - lastPointer.x) + * mLocked.pointerGestureXMovementScale; + float deltaY = (currentPointer.y - lastPointer.y) + * mLocked.pointerGestureYMovementScale; + mPointerController->move(deltaX, deltaY); } + } - // Orientation - float orientation; - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - orientation = in.orientation * mLocked.orientationScale; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: { - int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); - int32_t c2 = signExtendNybble(in.orientation & 0x0f); - if (c1 != 0 || c2 != 0) { - orientation = atan2f(c1, c2) * 0.5f; - float scale = 1.0f + pythag(c1, c2) / 16.0f; - touchMajor *= scale; - touchMinor /= scale; - toolMajor *= scale; - toolMinor /= scale; + float x, y; + mPointerController->getPosition(&x, &y); + + mPointerGesture.currentGestureMode = PointerGesture::CLICK_OR_DRAG; + mPointerGesture.currentGesturePointerCount = 1; + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + } else if (mCurrentTouch.pointerCount == 0) { + // Case 3. No fingers down and button is not pressed. (NEUTRAL) + *outFinishPreviousGesture = true; + + // Watch for taps coming out of HOVER or INDETERMINATE_MULTITOUCH mode. + bool tapped = false; + if (mPointerGesture.lastGestureMode == PointerGesture::HOVER + || mPointerGesture.lastGestureMode + == PointerGesture::INDETERMINATE_MULTITOUCH) { + if (when <= mPointerGesture.tapTime + TAP_INTERVAL) { + float x, y; + mPointerController->getPosition(&x, &y); + if (fabs(x - mPointerGesture.initialPointerX) <= TAP_SLOP + && fabs(y - mPointerGesture.initialPointerY) <= TAP_SLOP) { +#if DEBUG_GESTURES + LOGD("Gestures: TAP"); +#endif + mPointerGesture.activeGestureId = 0; + mPointerGesture.currentGestureMode = PointerGesture::TAP; + mPointerGesture.currentGesturePointerCount = 1; + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit( + mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[ + mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue( + AMOTION_EVENT_AXIS_X, mPointerGesture.initialPointerX); + mPointerGesture.currentGestureCoords[0].setAxisValue( + AMOTION_EVENT_AXIS_Y, mPointerGesture.initialPointerY); + mPointerGesture.currentGestureCoords[0].setAxisValue( + AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + tapped = true; } else { - orientation = 0; +#if DEBUG_GESTURES + LOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", + x - mPointerGesture.initialPointerX, + y - mPointerGesture.initialPointerY); +#endif } - break; + } else { +#if DEBUG_GESTURES + LOGD("Gestures: Not a TAP, delay=%lld", + when - mPointerGesture.tapTime); +#endif } - default: - orientation = 0; + } + if (!tapped) { +#if DEBUG_GESTURES + LOGD("Gestures: NEUTRAL"); +#endif + mPointerGesture.activeGestureId = -1; + mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; + mPointerGesture.currentGesturePointerCount = 0; + mPointerGesture.currentGestureIdBits.clear(); + } + } else if (mCurrentTouch.pointerCount == 1) { + // Case 4. Exactly one finger down, button is not pressed. (HOVER) + // The pointer follows the active touch point. + // Emit HOVER_MOVE events at the pointer location. + assert(activeTouchId >= 0); + +#if DEBUG_GESTURES + LOGD("Gestures: HOVER"); +#endif + + if (mLastTouch.idBits.hasBit(activeTouchId)) { + const PointerData& currentPointer = + mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]]; + const PointerData& lastPointer = + mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]]; + float deltaX = (currentPointer.x - lastPointer.x) + * mLocked.pointerGestureXMovementScale; + float deltaY = (currentPointer.y - lastPointer.y) + * mLocked.pointerGestureYMovementScale; + mPointerController->move(deltaX, deltaY); + } + + *outFinishPreviousGesture = true; + mPointerGesture.activeGestureId = 0; + + float x, y; + mPointerController->getPosition(&x, &y); + + mPointerGesture.currentGestureMode = PointerGesture::HOVER; + mPointerGesture.currentGesturePointerCount = 1; + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f); + + if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) { + mPointerGesture.tapTime = when; + mPointerGesture.initialPointerX = x; + mPointerGesture.initialPointerY = y; + } + } else { + // Case 5. At least two fingers down, button is not pressed. (SWIPE or FREEFORM + // or INDETERMINATE_MULTITOUCH) + // Initially we watch and wait for something interesting to happen so as to + // avoid making a spurious guess as to the nature of the gesture. For example, + // the fingers may be in transition to some other state such as pressing or + // releasing the button or we may be performing a two finger tap. + // + // Fix the centroid of the figure when the gesture actually starts. + // We do not recalculate the centroid at any other time during the gesture because + // it would affect the relationship of the touch points relative to the pointer location. + assert(activeTouchId >= 0); + + uint32_t currentTouchPointerCount = mCurrentTouch.pointerCount; + if (currentTouchPointerCount > MAX_POINTERS) { + currentTouchPointerCount = MAX_POINTERS; + } + + if (mPointerGesture.lastGestureMode != PointerGesture::INDETERMINATE_MULTITOUCH + && mPointerGesture.lastGestureMode != PointerGesture::SWIPE + && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { + mPointerGesture.currentGestureMode = PointerGesture::INDETERMINATE_MULTITOUCH; + + *outFinishPreviousGesture = true; + mPointerGesture.activeGestureId = -1; + + // Remember the initial pointer location. + // Everything we do will be relative to this location. + mPointerController->getPosition(&mPointerGesture.initialPointerX, + &mPointerGesture.initialPointerY); + + // Track taps. + if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) { + mPointerGesture.tapTime = when; } - // X and Y - // Adjust coords for surface orientation. - float x, y; - switch (mLocked.surfaceOrientation) { - case DISPLAY_ORIENTATION_90: - x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale; - y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale; - orientation -= M_PI_2; - if (orientation < - M_PI_2) { - orientation += M_PI; - } - break; - case DISPLAY_ORIENTATION_180: - x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale; - y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale; - break; - case DISPLAY_ORIENTATION_270: - x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale; - y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale; - orientation += M_PI_2; - if (orientation > M_PI_2) { - orientation -= M_PI; + // Reset the touch origin to be relative to exactly where the fingers are now + // in case they have moved some distance away as part of a previous gesture. + // We want to know how far the fingers have traveled since we started considering + // a multitouch gesture. + mPointerGesture.touchOrigin.copyFrom(mCurrentTouch); + } else { + mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; + } + + if (mPointerGesture.currentGestureMode == PointerGesture::INDETERMINATE_MULTITOUCH) { + // Wait for the pointers to start moving before doing anything. + bool decideNow = true; + for (uint32_t i = 0; i < currentTouchPointerCount; i++) { + const PointerData& current = mCurrentTouch.pointers[i]; + const PointerData& origin = mPointerGesture.touchOrigin.pointers[ + mPointerGesture.touchOrigin.idToIndex[current.id]]; + float distance = pythag( + (current.x - origin.x) * mLocked.pointerGestureXZoomScale, + (current.y - origin.y) * mLocked.pointerGestureYZoomScale); + if (distance < MULTITOUCH_MIN_TRAVEL) { + decideNow = false; + break; } - break; - default: - x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale; - y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale; - break; } - // Write output coords. - PointerCoords& out = pointerCoords[outIndex]; - out.clear(); - out.setAxisValue(AMOTION_EVENT_AXIS_X, x); - out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); - out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); - - pointerIds[outIndex] = int32_t(id); - - if (id == changedId) { - motionEventAction |= outIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + if (decideNow) { + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + if (currentTouchPointerCount == 2 + && distanceSquared( + mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y, + mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y) + <= mLocked.pointerGestureMaxSwipeWidthSquared) { + const PointerData& current1 = mCurrentTouch.pointers[0]; + const PointerData& current2 = mCurrentTouch.pointers[1]; + const PointerData& origin1 = mPointerGesture.touchOrigin.pointers[ + mPointerGesture.touchOrigin.idToIndex[current1.id]]; + const PointerData& origin2 = mPointerGesture.touchOrigin.pointers[ + mPointerGesture.touchOrigin.idToIndex[current2.id]]; + + float x1 = (current1.x - origin1.x) * mLocked.pointerGestureXZoomScale; + float y1 = (current1.y - origin1.y) * mLocked.pointerGestureYZoomScale; + float x2 = (current2.x - origin2.x) * mLocked.pointerGestureXZoomScale; + float y2 = (current2.y - origin2.y) * mLocked.pointerGestureYZoomScale; + float magnitude1 = pythag(x1, y1); + float magnitude2 = pythag(x2, y2); + + // Calculate the dot product of the vectors. + // When the vectors are oriented in approximately the same direction, + // the angle betweeen them is near zero and the cosine of the angle + // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). + // We know that the magnitude is at least MULTITOUCH_MIN_TRAVEL because + // we checked it above. + float dot = x1 * x2 + y1 * y2; + float cosine = dot / (magnitude1 * magnitude2); // denominator always > 0 + if (cosine > SWIPE_TRANSITION_ANGLE_COSINE) { + mPointerGesture.currentGestureMode = PointerGesture::SWIPE; + } + } + + // Remember the initial centroid for the duration of the gesture. + mPointerGesture.initialCentroidX = 0; + mPointerGesture.initialCentroidY = 0; + for (uint32_t i = 0; i < currentTouchPointerCount; i++) { + const PointerData& touch = mCurrentTouch.pointers[i]; + mPointerGesture.initialCentroidX += touch.x; + mPointerGesture.initialCentroidY += touch.y; + } + mPointerGesture.initialCentroidX /= int32_t(currentTouchPointerCount); + mPointerGesture.initialCentroidY /= int32_t(currentTouchPointerCount); + + mPointerGesture.activeGestureId = 0; + } + } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { + // Switch to FREEFORM if additional pointers go down. + if (currentTouchPointerCount > 2) { + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } } - // Check edge flags by looking only at the first pointer since the flags are - // global to the event. - if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) { - uint32_t inIndex = touch->idToIndex[pointerIds[0]]; - const PointerData& in = touch->pointers[inIndex]; + if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { + // SWIPE mode. +#if DEBUG_GESTURES + LOGD("Gestures: SWIPE activeTouchId=%d," + "activeGestureId=%d, currentTouchPointerCount=%d", + activeTouchId, mPointerGesture.activeGestureId, currentTouchPointerCount); +#endif + assert(mPointerGesture.activeGestureId >= 0); + + float x = (mCurrentTouch.pointers[0].x + mCurrentTouch.pointers[1].x + - mPointerGesture.initialCentroidX * 2) * 0.5f + * mLocked.pointerGestureXMovementScale + mPointerGesture.initialPointerX; + float y = (mCurrentTouch.pointers[0].y + mCurrentTouch.pointers[1].y + - mPointerGesture.initialCentroidY * 2) * 0.5f + * mLocked.pointerGestureYMovementScale + mPointerGesture.initialPointerY; + + mPointerGesture.currentGesturePointerCount = 1; + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { + // FREEFORM mode. +#if DEBUG_GESTURES + LOGD("Gestures: FREEFORM activeTouchId=%d," + "activeGestureId=%d, currentTouchPointerCount=%d", + activeTouchId, mPointerGesture.activeGestureId, currentTouchPointerCount); +#endif + assert(mPointerGesture.activeGestureId >= 0); + + mPointerGesture.currentGesturePointerCount = currentTouchPointerCount; + mPointerGesture.currentGestureIdBits.clear(); + + BitSet32 mappedTouchIdBits; + BitSet32 usedGestureIdBits; + if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { + // Initially, assign the active gesture id to the active touch point + // if there is one. No other touch id bits are mapped yet. + if (!*outCancelPreviousGesture) { + mappedTouchIdBits.markBit(activeTouchId); + usedGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = + mPointerGesture.activeGestureId; + } else { + mPointerGesture.activeGestureId = -1; + } + } else { + // Otherwise, assume we mapped all touches from the previous frame. + // Reuse all mappings that are still applicable. + mappedTouchIdBits.value = mLastTouch.idBits.value & mCurrentTouch.idBits.value; + usedGestureIdBits = mPointerGesture.lastGestureIdBits; + + // Check whether we need to choose a new active gesture id because the + // current went went up. + for (BitSet32 upTouchIdBits(mLastTouch.idBits.value & ~mCurrentTouch.idBits.value); + !upTouchIdBits.isEmpty(); ) { + uint32_t upTouchId = upTouchIdBits.firstMarkedBit(); + upTouchIdBits.clearBit(upTouchId); + uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; + if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { + mPointerGesture.activeGestureId = -1; + break; + } + } + } - if (in.x <= mRawAxes.x.minValue) { - motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT, - mLocked.surfaceOrientation); - } else if (in.x >= mRawAxes.x.maxValue) { - motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT, - mLocked.surfaceOrientation); +#if DEBUG_GESTURES + LOGD("Gestures: FREEFORM follow up " + "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " + "activeGestureId=%d", + mappedTouchIdBits.value, usedGestureIdBits.value, + mPointerGesture.activeGestureId); +#endif + + for (uint32_t i = 0; i < currentTouchPointerCount; i++) { + uint32_t touchId = mCurrentTouch.pointers[i].id; + uint32_t gestureId; + if (!mappedTouchIdBits.hasBit(touchId)) { + gestureId = usedGestureIdBits.firstUnmarkedBit(); + usedGestureIdBits.markBit(gestureId); + mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; +#if DEBUG_GESTURES + LOGD("Gestures: FREEFORM " + "new mapping for touch id %d -> gesture id %d", + touchId, gestureId); +#endif + } else { + gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; +#if DEBUG_GESTURES + LOGD("Gestures: FREEFORM " + "existing mapping for touch id %d -> gesture id %d", + touchId, gestureId); +#endif + } + mPointerGesture.currentGestureIdBits.markBit(gestureId); + mPointerGesture.currentGestureIdToIndex[gestureId] = i; + + float x = (mCurrentTouch.pointers[i].x - mPointerGesture.initialCentroidX) + * mLocked.pointerGestureXZoomScale + mPointerGesture.initialPointerX; + float y = (mCurrentTouch.pointers[i].y - mPointerGesture.initialCentroidY) + * mLocked.pointerGestureYZoomScale + mPointerGesture.initialPointerY; + + mPointerGesture.currentGestureCoords[i].clear(); + mPointerGesture.currentGestureCoords[i].setAxisValue( + AMOTION_EVENT_AXIS_X, x); + mPointerGesture.currentGestureCoords[i].setAxisValue( + AMOTION_EVENT_AXIS_Y, y); + mPointerGesture.currentGestureCoords[i].setAxisValue( + AMOTION_EVENT_AXIS_PRESSURE, 1.0f); } - if (in.y <= mRawAxes.y.minValue) { - motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP, - mLocked.surfaceOrientation); - } else if (in.y >= mRawAxes.y.maxValue) { - motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM, - mLocked.surfaceOrientation); + + if (mPointerGesture.activeGestureId < 0) { + mPointerGesture.activeGestureId = + mPointerGesture.currentGestureIdBits.firstMarkedBit(); +#if DEBUG_GESTURES + LOGD("Gestures: FREEFORM new " + "activeGestureId=%d", mPointerGesture.activeGestureId); +#endif } + } else { + // INDETERMINATE_MULTITOUCH mode. + // Do nothing. +#if DEBUG_GESTURES + LOGD("Gestures: INDETERMINATE_MULTITOUCH"); +#endif } + } - xPrecision = mLocked.orientedXPrecision; - yPrecision = mLocked.orientedYPrecision; - } // release lock + // Unfade the pointer if the user is doing anything with the touch pad. + mPointerController->setButtonState(mCurrentTouch.buttonState); + if (mCurrentTouch.buttonState || mCurrentTouch.pointerCount != 0) { + mPointerController->unfade(); + } + +#if DEBUG_GESTURES + LOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " + "currentGestureMode=%d, currentGesturePointerCount=%d, currentGestureIdBits=0x%08x, " + "lastGestureMode=%d, lastGesturePointerCount=%d, lastGestureIdBits=0x%08x", + toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), + mPointerGesture.currentGestureMode, mPointerGesture.currentGesturePointerCount, + mPointerGesture.currentGestureIdBits.value, + mPointerGesture.lastGestureMode, mPointerGesture.lastGesturePointerCount, + mPointerGesture.lastGestureIdBits.value); + for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; + LOGD(" currentGesture[%d]: index=%d, x=%0.3f, y=%0.3f, pressure=%0.3f", + id, index, coords.getAxisValue(AMOTION_EVENT_AXIS_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_Y), + coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); + } + for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; + const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; + LOGD(" lastGesture[%d]: index=%d, x=%0.3f, y=%0.3f, pressure=%0.3f", + id, index, coords.getAxisValue(AMOTION_EVENT_AXIS_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_Y), + coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); + } +#endif +} + +void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, + int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags, + const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, + int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { + PointerCoords pointerCoords[MAX_POINTERS]; + int32_t pointerIds[MAX_POINTERS]; + uint32_t pointerCount = 0; + while (!idBits.isEmpty()) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + uint32_t index = idToIndex[id]; + pointerIds[pointerCount] = id; + pointerCoords[pointerCount].copyFrom(coords[index]); + + if (changedId >= 0 && id == uint32_t(changedId)) { + action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + } + + pointerCount += 1; + } + + assert(pointerCount != 0); - getDispatcher()->notifyMotion(when, getDeviceId(), mTouchSource, policyFlags, - motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags, - pointerCount, pointerIds, pointerCoords, - xPrecision, yPrecision, mDownTime); + if (changedId >= 0 && pointerCount == 1) { + // Replace initial down and final up action. + // We can compare the action without masking off the changed pointer index + // because we know the index is 0. + if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { + action = AMOTION_EVENT_ACTION_DOWN; + } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { + action = AMOTION_EVENT_ACTION_UP; + } else { + // Can't happen. + assert(false); + } + } + + getDispatcher()->notifyMotion(when, getDeviceId(), source, policyFlags, + action, flags, metaState, edgeFlags, + pointerCount, pointerIds, pointerCoords, xPrecision, yPrecision, downTime); +} + +bool TouchInputMapper::updateMovedPointerCoords( + const PointerCoords* inCoords, const uint32_t* inIdToIndex, + PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const { + bool changed = false; + while (!idBits.isEmpty()) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + + uint32_t inIndex = inIdToIndex[id]; + uint32_t outIndex = outIdToIndex[id]; + const PointerCoords& curInCoords = inCoords[inIndex]; + PointerCoords& curOutCoords = outCoords[outIndex]; + + if (curInCoords != curOutCoords) { + curOutCoords.copyFrom(curInCoords); + changed = true; + } + } + return changed; +} + +void TouchInputMapper::fadePointer() { + { // acquire lock + AutoMutex _l(mLock); + if (mPointerController != NULL) { + mPointerController->fade(); + } + } // release lock } bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) { @@ -3592,6 +4584,7 @@ void SingleTouchInputMapper::initialize() { mY = 0; mPressure = 0; // default to 0 for devices that don't report pressure mToolWidth = 0; // default to 0 for devices that don't report tool width + mButtonState = 0; } void SingleTouchInputMapper::reset() { @@ -3611,6 +4604,19 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { // not have received valid position information yet. This logic assumes that // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet. break; + default: + if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { + uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); + if (buttonState) { + if (rawEvent->value) { + mAccumulator.buttonDown |= buttonState; + } else { + mAccumulator.buttonUp |= buttonState; + } + mAccumulator.fields |= Accumulator::FIELD_BUTTONS; + } + } + break; } break; @@ -3671,6 +4677,10 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mToolWidth = mAccumulator.absToolWidth; } + if (fields & Accumulator::FIELD_BUTTONS) { + mButtonState = (mButtonState | mAccumulator.buttonDown) & ~mAccumulator.buttonUp; + } + mCurrentTouch.clear(); if (mDown) { @@ -3686,6 +4696,7 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.pointers[0].orientation = 0; mCurrentTouch.idToIndex[0] = 0; mCurrentTouch.idBits.markBit(0); + mCurrentTouch.buttonState = mButtonState; } syncTouch(when, true); @@ -3715,6 +4726,7 @@ MultiTouchInputMapper::~MultiTouchInputMapper() { void MultiTouchInputMapper::initialize() { mAccumulator.clear(); + mButtonState = 0; } void MultiTouchInputMapper::reset() { @@ -3725,6 +4737,20 @@ void MultiTouchInputMapper::reset() { void MultiTouchInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { + case EV_KEY: { + if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { + uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); + if (buttonState) { + if (rawEvent->value) { + mAccumulator.buttonDown |= buttonState; + } else { + mAccumulator.buttonUp |= buttonState; + } + } + } + break; + } + case EV_ABS: { uint32_t pointerIndex = mAccumulator.pointerCount; Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex]; @@ -3902,6 +4928,9 @@ void MultiTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.pointerCount = outCount; + mButtonState = (mButtonState | mAccumulator.buttonDown) & ~mAccumulator.buttonUp; + mCurrentTouch.buttonState = mButtonState; + syncTouch(when, havePointerIds); mAccumulator.clear(); diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 68002ca..cf9b13d 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -159,6 +159,8 @@ public: virtual void fadePointer() = 0; + virtual void requestTimeoutAtTime(nsecs_t when) = 0; + virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputDispatcherInterface* getDispatcher() = 0; virtual EventHubInterface* getEventHub() = 0; @@ -214,6 +216,10 @@ private: virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); } virtual EventHubInterface* getEventHub() { return mEventHub.get(); } + // The event queue. + static const int EVENT_BUFFER_SIZE = 256; + RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; + // This reader/writer lock guards the list of input devices. // The writer lock must be held whenever the list of input devices is modified // and then promptly released. @@ -226,15 +232,15 @@ private: KeyedVector<int32_t, InputDevice*> mDevices; // low-level input event decoding and device management - void process(const RawEvent* rawEvent); + void processEvents(const RawEvent* rawEvents, size_t count); void addDevice(int32_t deviceId); void removeDevice(int32_t deviceId); - void configureExcludedDevices(); - - void consumeEvent(const RawEvent* rawEvent); + void processEventsForDevice(int32_t deviceId, const RawEvent* rawEvents, size_t count); + void timeoutExpired(nsecs_t when); void handleConfigurationChanged(nsecs_t when); + void configureExcludedDevices(); // state management for all devices Mutex mStateLock; @@ -248,11 +254,14 @@ private: InputConfiguration mInputConfiguration; void updateInputConfiguration(); - nsecs_t mDisableVirtualKeysTimeout; + nsecs_t mDisableVirtualKeysTimeout; // only accessed by reader thread virtual void disableVirtualKeysUntil(nsecs_t time); virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode); + nsecs_t mNextTimeout; // only accessed by reader thread + virtual void requestTimeoutAtTime(nsecs_t when); + // state queries typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code, @@ -295,7 +304,8 @@ public: void addMapper(InputMapper* mapper); void configure(); void reset(); - void process(const RawEvent* rawEvent); + void process(const RawEvent* rawEvents, size_t count); + void timeoutExpired(nsecs_t when); void getDeviceInfo(InputDeviceInfo* outDeviceInfo); int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); @@ -352,6 +362,7 @@ public: virtual void configure(); virtual void reset(); virtual void process(const RawEvent* rawEvent) = 0; + virtual void timeoutExpired(nsecs_t when); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); @@ -558,6 +569,8 @@ public: virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); + virtual void fadePointer(); + protected: Mutex mLock; @@ -611,10 +624,12 @@ protected: PointerData pointers[MAX_POINTERS]; BitSet32 idBits; uint32_t idToIndex[MAX_POINTER_ID + 1]; + uint32_t buttonState; void copyFrom(const TouchData& other) { pointerCount = other.pointerCount; idBits = other.idBits; + buttonState = other.buttonState; for (uint32_t i = 0; i < pointerCount; i++) { pointers[i] = other.pointers[i]; @@ -627,17 +642,20 @@ protected: inline void clear() { pointerCount = 0; idBits.clear(); + buttonState = 0; } }; // Input sources supported by the device. uint32_t mTouchSource; // sources when reporting touch data + uint32_t mPointerSource; // sources when reporting pointer gestures // Immutable configuration parameters. struct Parameters { enum DeviceType { DEVICE_TYPE_TOUCH_SCREEN, DEVICE_TYPE_TOUCH_PAD, + DEVICE_TYPE_POINTER, }; DeviceType deviceType; @@ -735,11 +753,17 @@ protected: // Current and previous touch sample data. TouchData mCurrentTouch; + PointerCoords mCurrentTouchCoords[MAX_POINTERS]; + TouchData mLastTouch; + PointerCoords mLastTouchCoords[MAX_POINTERS]; // The time the primary pointer last went down. nsecs_t mDownTime; + // The pointer controller, or null if the device is not a pointer. + sp<PointerControllerInterface> mPointerController; + struct LockedState { Vector<VirtualKey> virtualKeys; @@ -804,6 +828,17 @@ protected: int32_t keyCode; int32_t scanCode; } currentVirtualKey; + + // Scale factor for gesture based pointer movements. + float pointerGestureXMovementScale; + float pointerGestureYMovementScale; + + // Scale factor for gesture based zooming and other freeform motions. + float pointerGestureXZoomScale; + float pointerGestureYZoomScale; + + // The maximum swipe width squared. + int32_t pointerGestureMaxSwipeWidthSquared; } mLocked; virtual void configureParameters(); @@ -869,13 +904,148 @@ private: uint64_t distance : 48; // squared distance }; + struct PointerGesture { + enum Mode { + // No fingers, button is not pressed. + // Nothing happening. + NEUTRAL, + + // No fingers, button is not pressed. + // Tap detected. + // Emits DOWN and UP events at the pointer location. + TAP, + + // Button is pressed. + // Pointer follows the active finger if there is one. Other fingers are ignored. + // Emits DOWN, MOVE and UP events at the pointer location. + CLICK_OR_DRAG, + + // Exactly one finger, button is not pressed. + // Pointer follows the active finger. + // Emits HOVER_MOVE events at the pointer location. + HOVER, + + // More than two fingers involved but they haven't moved enough for us + // to figure out what is intended. + INDETERMINATE_MULTITOUCH, + + // Exactly two fingers moving in the same direction, button is not pressed. + // Pointer does not move. + // Emits DOWN, MOVE and UP events with a single pointer coordinate that + // follows the midpoint between both fingers. + // The centroid is fixed when entering this state. + SWIPE, + + // Two or more fingers moving in arbitrary directions, button is not pressed. + // Pointer does not move. + // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow + // each finger individually relative to the initial centroid of the finger. + // The centroid is fixed when entering this state. + FREEFORM, + + // Waiting for quiet time to end before starting the next gesture. + QUIET, + }; + + // The active pointer id from the raw touch data. + int32_t activeTouchId; // -1 if none + + // The active pointer id from the gesture last delivered to the application. + int32_t activeGestureId; // -1 if none + + // Pointer coords and ids for the current and previous pointer gesture. + Mode currentGestureMode; + uint32_t currentGesturePointerCount; + BitSet32 currentGestureIdBits; + uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; + PointerCoords currentGestureCoords[MAX_POINTERS]; + + Mode lastGestureMode; + uint32_t lastGesturePointerCount; + BitSet32 lastGestureIdBits; + uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; + PointerCoords lastGestureCoords[MAX_POINTERS]; + + // Tracks for all pointers originally went down. + TouchData touchOrigin; + + // Describes how touch ids are mapped to gesture ids for freeform gestures. + uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; + + // Initial centroid of the movement. + // Used to calculate how far the touch pointers have moved since the gesture started. + int32_t initialCentroidX; + int32_t initialCentroidY; + + // Initial pointer location. + // Used to track where the pointer was when the gesture started. + float initialPointerX; + float initialPointerY; + + // Time the pointer gesture last went down. + nsecs_t downTime; + + // Time we started waiting for a tap gesture. + nsecs_t tapTime; + + // Time we started waiting for quiescence. + nsecs_t quietTime; + + // A velocity tracker for determining whether to switch active pointers during drags. + VelocityTracker velocityTracker; + + void reset() { + activeTouchId = -1; + activeGestureId = -1; + currentGestureMode = NEUTRAL; + currentGesturePointerCount = 0; + currentGestureIdBits.clear(); + lastGestureMode = NEUTRAL; + lastGesturePointerCount = 0; + lastGestureIdBits.clear(); + touchOrigin.clear(); + initialCentroidX = 0; + initialCentroidY = 0; + initialPointerX = 0; + initialPointerY = 0; + downTime = 0; + velocityTracker.clear(); + resetTapTime(); + resetQuietTime(); + } + + void resetTapTime() { + tapTime = LLONG_MIN; + } + + void resetQuietTime() { + quietTime = LLONG_MIN; + } + } mPointerGesture; + void initializeLocked(); TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags); void dispatchTouches(nsecs_t when, uint32_t policyFlags); - void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch, - BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, - int32_t motionEventAction); + void prepareTouches(int32_t* outEdgeFlags, float* outXPrecision, float* outYPrecision); + void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags); + void preparePointerGestures(nsecs_t when, + bool* outCancelPreviousGesture, bool* outFinishPreviousGesture); + + // Dispatches a motion event. + // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the + // method will take care of setting the index and transmuting the action to DOWN or UP + // it is the first / last pointer to go down / up. + void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, + int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags, + const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, + int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); + + // Updates pointer coords for pointers with specified ids that have moved. + // Returns true if any of them changed. + bool updateMovedPointerCoords(const PointerCoords* inCoords, const uint32_t* inIdToIndex, + PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const; + void suppressSwipeOntoVirtualKeys(nsecs_t when); bool isPointInsideSurfaceLocked(int32_t x, int32_t y); @@ -907,6 +1077,7 @@ private: FIELD_ABS_Y = 4, FIELD_ABS_PRESSURE = 8, FIELD_ABS_TOOL_WIDTH = 16, + FIELD_BUTTONS = 32, }; uint32_t fields; @@ -917,8 +1088,13 @@ private: int32_t absPressure; int32_t absToolWidth; + uint32_t buttonDown; + uint32_t buttonUp; + inline void clear() { fields = 0; + buttonDown = 0; + buttonUp = 0; } } mAccumulator; @@ -927,6 +1103,7 @@ private: int32_t mY; int32_t mPressure; int32_t mToolWidth; + uint32_t mButtonState; void initialize(); @@ -978,12 +1155,20 @@ private: } } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks + // Bitfield of buttons that went down or up. + uint32_t buttonDown; + uint32_t buttonUp; + inline void clear() { pointerCount = 0; pointers[0].clear(); + buttonDown = 0; + buttonUp = 0; } } mAccumulator; + uint32_t mButtonState; + void initialize(); void sync(nsecs_t when); diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk index 799eb76..cabbccb 100644 --- a/services/input/tests/Android.mk +++ b/services/input/tests/Android.mk @@ -15,7 +15,6 @@ shared_libraries := \ libhardware \ libhardware_legacy \ libui \ - libsurfaceflinger_client \ libskia \ libstlport \ libinput diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 32982c4..60549c6 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -622,14 +622,14 @@ private: mExcludedDevices.add(String8(deviceName)); } - virtual bool getEvent(RawEvent* outEvent) { + virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { if (mEvents.empty()) { - return false; + return 0; } - *outEvent = *mEvents.begin(); + *buffer = *mEvents.begin(); mEvents.erase(mEvents.begin()); - return true; + return 1; } virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const { @@ -780,6 +780,9 @@ private: virtual void fadePointer() { } + + virtual void requestTimeoutAtTime(nsecs_t when) { + } }; @@ -1442,7 +1445,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe // Event handling. RawEvent event; - mDevice->process(&event); + mDevice->process(&event, 1); ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); @@ -2460,8 +2463,18 @@ void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { } -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecified_ReturnsTouchPad) { +TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); + prepareAxes(POSITION); + addMapperAndConfigure(mapper); + + ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); +} + +TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); + mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X); + mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y); prepareAxes(POSITION); addMapperAndConfigure(mapper); diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index a4a95a0..c03b994 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -541,7 +541,9 @@ class AppWidgetService extends IAppWidgetService.Stub IRemoteViewsFactory.Stub.asInterface(service); try { cb.onDestroy(intent); - } catch (Exception e) { + } catch (RemoteException e) { + e.printStackTrace(); + } catch (RuntimeException e) { e.printStackTrace(); } mContext.unbindService(this); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index f170cb7..12ac052 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -24,6 +24,7 @@ import android.content.pm.PackageManager; import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.DummyDataStateTracker; +import android.net.EthernetDataTracker; import android.net.IConnectivityManager; import android.net.LinkProperties; import android.net.MobileDataStateTracker; @@ -420,6 +421,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance(); mNetTrackers[netType].startMonitoring(context, mHandler); break; + case ConnectivityManager.TYPE_ETHERNET: + mNetTrackers[netType] = EthernetDataTracker.getInstance(); + mNetTrackers[netType].startMonitoring(context, mHandler); + break; default: loge("Trying to create a DataStateTracker for an unknown radio type " + mNetAttributes[netType].mRadio); diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java index 0fba7c3..fc5443e 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -56,7 +56,7 @@ import android.util.Slog; * settings parameter with a default value of 2MB), the free memory is * logged to the event log. */ -class DeviceStorageMonitorService extends Binder { +public class DeviceStorageMonitorService extends Binder { private static final String TAG = "DeviceStorageMonitorService"; private static final boolean DEBUG = false; private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; @@ -99,7 +99,7 @@ class DeviceStorageMonitorService extends Binder { /** * This string is used for ServiceManager access to this class. */ - static final String SERVICE = "devicestoragemonitor"; + public static final String SERVICE = "devicestoragemonitor"; /** * Handler that checks the amount of disk space on the device and sends a @@ -398,4 +398,24 @@ class DeviceStorageMonitorService extends Binder { // force an early check postCheckMemoryMsg(true, 0); } + + /** + * Callable from other things in the system service to obtain the low memory + * threshold. + * + * @return low memory threshold in bytes + */ + public long getMemoryLowThreshold() { + return mMemLowThreshold; + } + + /** + * Callable from other things in the system process to check whether memory + * is low. + * + * @return true is memory is low + */ + public boolean isMemoryLow() { + return mLowMemFlag; + } } diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 91ada6b..4e80147 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -18,6 +18,7 @@ package com.android.server; import com.android.internal.app.IMediaContainerService; import com.android.server.am.ActivityManagerService; +import com.android.server.pm.PackageManagerService; import android.Manifest; import android.content.BroadcastReceiver; @@ -86,6 +87,9 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC private static final String VOLD_TAG = "VoldConnector"; + /** Maximum number of ASEC containers allowed to be mounted. */ + private static final int MAX_CONTAINERS = 250; + /* * Internal vold volume state constants */ @@ -483,7 +487,6 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC } } }; - private final class MountServiceBinderListener implements IBinder.DeathRecipient { final IMountServiceListener mListener; @@ -1087,8 +1090,7 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC * amount of containers we'd ever expect to have. This keeps an * "asec list" from blocking a thread repeatedly. */ - mConnector = new NativeDaemonConnector(this, "vold", - PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG); + mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG); mReady = false; Thread thread = new Thread(mConnector, VOLD_TAG); thread.start(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index d160963..4e1bbac 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -17,6 +17,7 @@ package com.android.server; import com.android.server.am.ActivityManagerService; +import com.android.server.pm.PackageManagerService; import com.android.server.usb.UsbService; import com.android.server.wm.WindowManagerService; import com.android.internal.app.ShutdownThread; diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 0000237..915b679 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -235,6 +235,15 @@ public class WifiService extends IWifiManager.Stub { } break; } + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { + Slog.d(TAG, "Send failed, client connection lost"); + } else { + Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + } + mClients.remove((AsyncChannel) msg.obj); + break; + } case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { AsyncChannel ac = new AsyncChannel(); ac.connect(mContext, this, msg.replyTo); diff --git a/services/java/com/android/server/pm/BasePermission.java b/services/java/com/android/server/pm/BasePermission.java new file mode 100644 index 0000000..4f27408 --- /dev/null +++ b/services/java/com/android/server/pm/BasePermission.java @@ -0,0 +1,59 @@ +/* + * 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 com.android.server.pm; + +import android.content.pm.PackageParser; +import android.content.pm.PermissionInfo; + +final class BasePermission { + final static int TYPE_NORMAL = 0; + + final static int TYPE_BUILTIN = 1; + + final static int TYPE_DYNAMIC = 2; + + final String name; + + String sourcePackage; + + PackageSettingBase packageSetting; + + final int type; + + int protectionLevel; + + PackageParser.Permission perm; + + PermissionInfo pendingInfo; + + int uid; + + int[] gids; + + BasePermission(String _name, String _sourcePackage, int _type) { + name = _name; + sourcePackage = _sourcePackage; + type = _type; + // Default to most conservative protection level. + protectionLevel = PermissionInfo.PROTECTION_SIGNATURE; + } + + public String toString() { + return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name + + "}"; + } +} diff --git a/services/java/com/android/server/pm/GrantedPermissions.java b/services/java/com/android/server/pm/GrantedPermissions.java new file mode 100644 index 0000000..c7629b9 --- /dev/null +++ b/services/java/com/android/server/pm/GrantedPermissions.java @@ -0,0 +1,50 @@ +/* + * 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.server.pm; + +import android.content.pm.ApplicationInfo; + +import java.util.HashSet; + +class GrantedPermissions { + int pkgFlags; + + HashSet<String> grantedPermissions = new HashSet<String>(); + + int[] gids; + + GrantedPermissions(int pkgFlags) { + setFlags(pkgFlags); + } + + @SuppressWarnings("unchecked") + GrantedPermissions(GrantedPermissions base) { + pkgFlags = base.pkgFlags; + grantedPermissions = (HashSet<String>) base.grantedPermissions.clone(); + + if (base.gids != null) { + gids = base.gids.clone(); + } + } + + void setFlags(int pkgFlags) { + this.pkgFlags = pkgFlags + & (ApplicationInfo.FLAG_SYSTEM + | ApplicationInfo.FLAG_FORWARD_LOCK + | ApplicationInfo.FLAG_EXTERNAL_STORAGE); + } +} diff --git a/services/java/com/android/server/Installer.java b/services/java/com/android/server/pm/Installer.java index 08d1b82..8d40000 100644 --- a/services/java/com/android/server/Installer.java +++ b/services/java/com/android/server/pm/Installer.java @@ -14,28 +14,31 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.pm; import android.content.pm.PackageStats; -import android.net.LocalSocketAddress; import android.net.LocalSocket; -import android.util.Config; +import android.net.LocalSocketAddress; import android.util.Slog; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.Socket; - class Installer { private static final String TAG = "Installer"; - InputStream mIn; - OutputStream mOut; - LocalSocket mSocket; - byte buf[] = new byte[1024]; - int buflen = 0; + private static final boolean LOCAL_DEBUG = true; + + InputStream mIn; + + OutputStream mOut; + + LocalSocket mSocket; + + byte buf[] = new byte[1024]; + + int buflen = 0; private boolean connect() { if (mSocket != null) { @@ -45,8 +48,8 @@ class Installer { try { mSocket = new LocalSocket(); - LocalSocketAddress address = new LocalSocketAddress( - "installd", LocalSocketAddress.Namespace.RESERVED); + LocalSocketAddress address = new LocalSocketAddress("installd", + LocalSocketAddress.Namespace.RESERVED); mSocket.connect(address); @@ -59,112 +62,131 @@ class Installer { return true; } - private void disconnect() { - Slog.i(TAG,"disconnecting..."); - try { - if (mSocket != null) mSocket.close(); - } catch (IOException ex) { } - try { - if (mIn != null) mIn.close(); - } catch (IOException ex) { } - try { - if (mOut != null) mOut.close(); - } catch (IOException ex) { } - mSocket = null; - mIn = null; - mOut = null; - } - - private boolean readBytes(byte buffer[], int len) { - int off = 0, count; - if (len < 0) return false; - while (off != len) { - try { - count = mIn.read(buffer, off, len - off); - if (count <= 0) { + private void disconnect() { + Slog.i(TAG, "disconnecting..."); + try { + if (mSocket != null) + mSocket.close(); + } catch (IOException ex) { + } + try { + if (mIn != null) + mIn.close(); + } catch (IOException ex) { + } + try { + if (mOut != null) + mOut.close(); + } catch (IOException ex) { + } + mSocket = null; + mIn = null; + mOut = null; + } + + private boolean readBytes(byte buffer[], int len) { + int off = 0, count; + if (len < 0) + return false; + while (off != len) { + try { + count = mIn.read(buffer, off, len - off); + if (count <= 0) { Slog.e(TAG, "read error " + count); break; } - off += count; - } catch (IOException ex) { - Slog.e(TAG,"read exception"); - break; - } - } -// Slog.i(TAG, "read "+len+" bytes"); - if (off == len) return true; - disconnect(); - return false; - } - - private boolean readReply() { - int len; - buflen = 0; - if (!readBytes(buf, 2)) return false; - len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); - if ((len < 1) || (len > 1024)) { - Slog.e(TAG,"invalid reply length ("+len+")"); - disconnect(); - return false; - } - if (!readBytes(buf, len)) return false; - buflen = len; - return true; - } - - private boolean writeCommand(String _cmd) { - byte[] cmd = _cmd.getBytes(); - int len = cmd.length; - if ((len < 1) || (len > 1024)) return false; - buf[0] = (byte) (len & 0xff); - buf[1] = (byte) ((len >> 8) & 0xff); - try { - mOut.write(buf, 0, 2); - mOut.write(cmd, 0, len); - } catch (IOException ex) { - Slog.e(TAG,"write error"); - disconnect(); - return false; - } - return true; - } - - private synchronized String transaction(String cmd) { - if (!connect()) { + off += count; + } catch (IOException ex) { + Slog.e(TAG, "read exception"); + break; + } + } + if (LOCAL_DEBUG) { + Slog.i(TAG, "read " + len + " bytes"); + } + if (off == len) + return true; + disconnect(); + return false; + } + + private boolean readReply() { + int len; + buflen = 0; + if (!readBytes(buf, 2)) + return false; + len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); + if ((len < 1) || (len > 1024)) { + Slog.e(TAG, "invalid reply length (" + len + ")"); + disconnect(); + return false; + } + if (!readBytes(buf, len)) + return false; + buflen = len; + return true; + } + + private boolean writeCommand(String _cmd) { + byte[] cmd = _cmd.getBytes(); + int len = cmd.length; + if ((len < 1) || (len > 1024)) + return false; + buf[0] = (byte) (len & 0xff); + buf[1] = (byte) ((len >> 8) & 0xff); + try { + mOut.write(buf, 0, 2); + mOut.write(cmd, 0, len); + } catch (IOException ex) { + Slog.e(TAG, "write error"); + disconnect(); + return false; + } + return true; + } + + private synchronized String transaction(String cmd) { + if (!connect()) { Slog.e(TAG, "connection failed"); return "-1"; } if (!writeCommand(cmd)) { - /* If installd died and restarted in the background - * (unlikely but possible) we'll fail on the next - * write (this one). Try to reconnect and write - * the command one more time before giving up. - */ + /* + * If installd died and restarted in the background (unlikely but + * possible) we'll fail on the next write (this one). Try to + * reconnect and write the command one more time before giving up. + */ Slog.e(TAG, "write command failed? reconnect!"); if (!connect() || !writeCommand(cmd)) { return "-1"; } } -// Slog.i(TAG,"send: '"+cmd+"'"); - if (readReply()) { + if (LOCAL_DEBUG) { + Slog.i(TAG, "send: '" + cmd + "'"); + } + if (readReply()) { String s = new String(buf, 0, buflen); -// Slog.i(TAG,"recv: '"+s+"'"); - return s; - } else { -// Slog.i(TAG,"fail"); - return "-1"; - } - } - - private int execute(String cmd) { - String res = transaction(cmd); - try { - return Integer.parseInt(res); - } catch (NumberFormatException ex) { - return -1; - } - } + if (LOCAL_DEBUG) { + Slog.i(TAG, "recv: '" + s + "'"); + } + return s; + } else { + if (LOCAL_DEBUG) { + Slog.i(TAG, "fail"); + } + return "-1"; + } + } + + private int execute(String cmd) { + String res = transaction(cmd); + try { + return Integer.parseInt(res); + } catch (NumberFormatException ex) { + return -1; + } + } public int install(String name, int uid, int gid) { StringBuilder builder = new StringBuilder("install"); @@ -225,14 +247,14 @@ class Installer { builder.append(name); return execute(builder.toString()); } - + public int clearUserData(String name) { StringBuilder builder = new StringBuilder("rmuserdata"); builder.append(' '); builder.append(name); return execute(builder.toString()); } - + public boolean ping() { if (execute("ping") < 0) { return false; @@ -240,7 +262,7 @@ class Installer { return true; } } - + public int freeCache(long freeStorageSize) { StringBuilder builder = new StringBuilder("freecache"); builder.append(' '); @@ -250,8 +272,8 @@ class Installer { /* * @param packagePathSuffix The name of the path relative to install - * directory. Say if the path name is /data/app/com.test-1.apk, - * the package suffix path will be com.test-1 + * directory. Say if the path name is /data/app/com.test-1.apk, the package + * suffix path will be com.test-1 */ public int setForwardLockPerm(String packagePathSuffix, int gid) { StringBuilder builder = new StringBuilder("protect"); @@ -261,7 +283,7 @@ class Installer { builder.append(gid); return execute(builder.toString()); } - + public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath, PackageStats pStats) { StringBuilder builder = new StringBuilder("getsize"); @@ -275,7 +297,7 @@ class Installer { String s = transaction(builder.toString()); String res[] = s.split(" "); - if((res == null) || (res.length != 4)) { + if ((res == null) || (res.length != 4)) { return -1; } try { @@ -286,7 +308,7 @@ class Installer { } catch (NumberFormatException e) { return -1; } - } + } public int moveFiles() { return execute("movefiles"); diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index d542673..669e060 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -14,26 +14,30 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.pm; + +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; -import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; +import com.android.server.DeviceStorageMonitorService; +import com.android.server.EventLogTags; +import com.android.server.IntentResolver; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.admin.IDevicePolicyManager; import android.app.backup.IBackupManager; -import android.content.Context; import android.content.ComponentName; +import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; import android.content.IntentFilter; @@ -42,7 +46,6 @@ import android.content.ServiceConnection; import android.content.IntentSender.SendIntentException; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; -import android.content.pm.ComponentInfo; import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; @@ -54,13 +57,10 @@ import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; -import android.content.pm.PackageStats; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import android.content.pm.PackageParser; -import android.content.pm.PermissionInfo; +import android.content.pm.PackageStats; import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -69,28 +69,32 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.Debug; +import android.os.Environment; +import android.os.FileObserver; +import android.os.FileUtils; +import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Parcel; -import android.os.RemoteException; -import android.os.Environment; -import android.os.FileObserver; -import android.os.FileUtils; -import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.security.SystemKeyStore; -import android.util.*; +import android.util.DisplayMetrics; +import android.util.EventLog; +import android.util.Log; +import android.util.LogPrinter; +import android.util.Slog; +import android.util.SparseArray; +import android.util.Xml; import android.view.Display; import android.view.WindowManager; -import java.io.BufferedOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -129,25 +133,29 @@ import java.util.zip.ZipOutputStream; mmm frameworks/base/tests/AndroidTests adb install -r -f out/target/product/passion/data/app/AndroidTests.apk adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner - * + * + * {@hide} */ -class PackageManagerService extends IPackageManager.Stub { - private static final String TAG = "PackageManager"; - private static final boolean DEBUG_SETTINGS = false; +public class PackageManagerService extends IPackageManager.Stub { + static final String TAG = "PackageManager"; + static final boolean DEBUG_SETTINGS = false; private static final boolean DEBUG_PREFERRED = false; - private static final boolean DEBUG_UPGRADE = false; + static final boolean DEBUG_UPGRADE = false; private static final boolean DEBUG_INSTALL = false; - private static final boolean DEBUG_STOPPED = false; - - private static final boolean MULTIPLE_APPLICATION_UIDS = true; + private static final boolean DEBUG_REMOVE = false; + private static final boolean DEBUG_SHOW_INFO = false; + private static final boolean DEBUG_PACKAGE_INFO = false; + private static final boolean DEBUG_INTENT_MATCHING = false; + private static final boolean DEBUG_PACKAGE_SCANNING = false; + private static final boolean DEBUG_APP_DIR_OBSERVER = false; + + static final boolean MULTIPLE_APPLICATION_UIDS = true; private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; private static final int NFC_UID = Process.NFC_UID; - private static final int FIRST_APPLICATION_UID = + static final int FIRST_APPLICATION_UID = Process.FIRST_APPLICATION_UID; - private static final int MAX_APPLICATION_UIDS = 1000; - - private static final boolean SHOW_INFO = false; + static final int MAX_APPLICATION_UIDS = 1000; private static final boolean GET_CERTIFICATES = true; @@ -161,19 +169,6 @@ class PackageManagerService extends IPackageManager.Stub { // package apks to install directory. private static final String INSTALL_PACKAGE_SUFFIX = "-"; - /** - * Indicates the state of installation. Used by PackageManager to - * figure out incomplete installations. Say a package is being installed - * (the state is set to PKG_INSTALL_INCOMPLETE) and remains so till - * the package installation is successful or unsuccesful lin which case - * the PackageManager will no longer maintain state information associated - * with the package. If some exception(like device freeze or battery being - * pulled out) occurs during installation of a package, the PackageManager - * needs this information to clean up the previously failed installation. - */ - private static final int PKG_INSTALL_INCOMPLETE = 0; - private static final int PKG_INSTALL_COMPLETE = 1; - static final int SCAN_MONITOR = 1<<0; static final int SCAN_NO_DEX = 1<<1; static final int SCAN_FORCE_DEX = 1<<2; @@ -362,6 +357,7 @@ class PackageManagerService extends IPackageManager.Stub { // Delay time in millisecs static final int BROADCAST_DELAY = 10 * 1000; + final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); class DefaultContainerConnection implements ServiceConnection { @@ -526,12 +522,12 @@ class PackageManagerService extends IPackageManager.Stub { } case MCS_GIVE_UP: { if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_giveup too many retries"); - HandlerParams params = mPendingInstalls.remove(0); + mPendingInstalls.remove(0); break; } case SEND_PENDING_BROADCAST : { String packages[]; - ArrayList components[]; + ArrayList<String> components[]; int size = 0; int uids[]; Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); @@ -563,8 +559,7 @@ class PackageManagerService extends IPackageManager.Stub { } // Send broadcasts for (int i = 0; i < size; i++) { - sendPackageChangedBroadcast(packages[i], true, - (ArrayList<String>)components[i], uids[i]); + sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); break; @@ -662,7 +657,7 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { removeMessages(WRITE_SETTINGS); removeMessages(WRITE_STOPPED_PACKAGES); - mSettings.writeLP(); + mSettings.writeLPr(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; @@ -670,7 +665,7 @@ class PackageManagerService extends IPackageManager.Stub { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mPackages) { removeMessages(WRITE_STOPPED_PACKAGES); - mSettings.writeStoppedLP(); + mSettings.writeStoppedLPr(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; @@ -742,17 +737,17 @@ class PackageManagerService extends IPackageManager.Stub { mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type")); mMetrics = new DisplayMetrics(); mSettings = new Settings(); - mSettings.addSharedUserLP("android.uid.system", + mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); - mSettings.addSharedUserLP("android.uid.phone", + mSettings.addSharedUserLPw("android.uid.phone", MULTIPLE_APPLICATION_UIDS ? RADIO_UID : FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); - mSettings.addSharedUserLP("android.uid.log", + mSettings.addSharedUserLPw("android.uid.log", MULTIPLE_APPLICATION_UIDS ? LOG_UID : FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); - mSettings.addSharedUserLP("android.uid.nfc", + mSettings.addSharedUserLPw("android.uid.nfc", MULTIPLE_APPLICATION_UIDS ? NFC_UID : FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); @@ -790,6 +785,7 @@ class PackageManagerService extends IPackageManager.Stub { d.getMetrics(mMetrics); synchronized (mInstallLock) { + // writer synchronized (mPackages) { mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); @@ -810,7 +806,7 @@ class PackageManagerService extends IPackageManager.Stub { readPermissions(); - mRestoredSettings = mSettings.readLP(); + mRestoredSettings = mSettings.readLPw(); long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, @@ -985,7 +981,7 @@ class PackageManagerService extends IPackageManager.Stub { mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists } //look for any incomplete package installations - ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackages(); + ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr(); //clean up list for(int i = 0; i < deletePkgsList.size(); i++) { //clean up here @@ -1026,9 +1022,10 @@ class PackageManagerService extends IPackageManager.Stub { + "; regranting permissions for internal storage"); mSettings.mInternalSdkPlatform = mSdkVersion; - updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions); + updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions); - mSettings.writeLP(); + // can downgrade to reader + mSettings.writeLPr(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); @@ -1078,7 +1075,7 @@ class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Unable to remove old code file: " + ps.resourcePath); } } - mSettings.removePackageLP(ps.name); + mSettings.removePackageLPw(ps.name); } void readPermissions() { @@ -1345,16 +1342,16 @@ class PackageManagerService extends IPackageManager.Stub { } public PackageInfo getPackageInfo(String packageName, int flags) { + // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); - if (Config.LOGV) Log.v( - TAG, "getPackageInfo " + packageName - + ": " + p); + if (DEBUG_PACKAGE_INFO) + Log.v(TAG, "getPackageInfo " + packageName + ": " + p); if (p != null) { return generatePackageInfo(p, flags); } if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - return generatePackageInfoFromSettingsLP(packageName, flags); + return generatePackageInfoFromSettingsLPw(packageName, flags); } } return null; @@ -1362,6 +1359,7 @@ class PackageManagerService extends IPackageManager.Stub { public String[] currentToCanonicalPackageNames(String[] names) { String[] out = new String[names.length]; + // reader synchronized (mPackages) { for (int i=names.length-1; i>=0; i--) { PackageSetting ps = mSettings.mPackages.get(names[i]); @@ -1373,6 +1371,7 @@ class PackageManagerService extends IPackageManager.Stub { public String[] canonicalToCurrentPackageNames(String[] names) { String[] out = new String[names.length]; + // reader synchronized (mPackages) { for (int i=names.length-1; i>=0; i--) { String cur = mSettings.mRenamedPackages.get(names[i]); @@ -1383,6 +1382,7 @@ class PackageManagerService extends IPackageManager.Stub { } public int getPackageUid(String packageName) { + // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if(p != null) { @@ -1398,11 +1398,11 @@ class PackageManagerService extends IPackageManager.Stub { } public int[] getPackageGids(String packageName) { + // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); - if (Config.LOGV) Log.v( - TAG, "getPackageGids" + packageName - + ": " + p); + if (DEBUG_PACKAGE_INFO) + Log.v(TAG, "getPackageGids" + packageName + ": " + p); if (p != null) { final PackageSetting ps = (PackageSetting)p.mExtras; final SharedUserSetting suid = ps.sharedUser; @@ -1427,6 +1427,7 @@ class PackageManagerService extends IPackageManager.Stub { } public PermissionInfo getPermissionInfo(String name, int flags) { + // reader synchronized (mPackages) { final BasePermission p = mSettings.mPermissions.get(name); if (p != null) { @@ -1437,6 +1438,7 @@ class PackageManagerService extends IPackageManager.Stub { } public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) { + // reader synchronized (mPackages) { ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10); for (BasePermission p : mSettings.mPermissions.values()) { @@ -1459,6 +1461,7 @@ class PackageManagerService extends IPackageManager.Stub { } public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) { + // reader synchronized (mPackages) { return PackageParser.generatePermissionGroupInfo( mPermissionGroups.get(name), flags); @@ -1466,6 +1469,7 @@ class PackageManagerService extends IPackageManager.Stub { } public List<PermissionGroupInfo> getAllPermissionGroups(int flags) { + // reader synchronized (mPackages) { final int N = mPermissionGroups.size(); ArrayList<PermissionGroupInfo> out @@ -1477,12 +1481,12 @@ class PackageManagerService extends IPackageManager.Stub { } } - private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) { + private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags) { PackageSetting ps = mSettings.mPackages.get(packageName); - if(ps != null) { - if(ps.pkg == null) { - PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags); - if(pInfo != null) { + if (ps != null) { + if (ps.pkg == null) { + PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags); + if (pInfo != null) { return pInfo.applicationInfo; } return null; @@ -1492,10 +1496,10 @@ class PackageManagerService extends IPackageManager.Stub { return null; } - private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) { + private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags) { PackageSetting ps = mSettings.mPackages.get(packageName); - if(ps != null) { - if(ps.pkg == null) { + if (ps != null) { + if (ps.pkg == null) { ps.pkg = new PackageParser.Package(packageName); ps.pkg.applicationInfo.packageName = packageName; ps.pkg.applicationInfo.flags = ps.pkgFlags; @@ -1512,9 +1516,10 @@ class PackageManagerService extends IPackageManager.Stub { } public ApplicationInfo getApplicationInfo(String packageName, int flags) { + // writer synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); - if (Config.LOGV) Log.v( + if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getApplicationInfo " + packageName + ": " + p); if (p != null) { @@ -1525,7 +1530,7 @@ class PackageManagerService extends IPackageManager.Stub { return mAndroidApplication; } if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - return generateApplicationInfoFromSettingsLP(packageName, flags); + return generateApplicationInfoFromSettingsLPw(packageName, flags); } } return null; @@ -1589,8 +1594,8 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { PackageParser.Activity a = mActivities.mActivities.get(component); - if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a); - if (a != null && mSettings.isEnabledLP(a.info, flags)) { + if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); + if (a != null && mSettings.isEnabledLPr(a.info, flags)) { return PackageParser.generateActivityInfo(a, flags); } if (mResolveComponentName.equals(component)) { @@ -1603,9 +1608,9 @@ class PackageManagerService extends IPackageManager.Stub { public ActivityInfo getReceiverInfo(ComponentName component, int flags) { synchronized (mPackages) { PackageParser.Activity a = mReceivers.mActivities.get(component); - if (Config.LOGV) Log.v( + if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getReceiverInfo " + component + ": " + a); - if (a != null && mSettings.isEnabledLP(a.info, flags)) { + if (a != null && mSettings.isEnabledLPr(a.info, flags)) { return PackageParser.generateActivityInfo(a, flags); } } @@ -1615,9 +1620,9 @@ class PackageManagerService extends IPackageManager.Stub { public ServiceInfo getServiceInfo(ComponentName component, int flags) { synchronized (mPackages) { PackageParser.Service s = mServices.mServices.get(component); - if (Config.LOGV) Log.v( + if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getServiceInfo " + component + ": " + s); - if (s != null && mSettings.isEnabledLP(s.info, flags)) { + if (s != null && mSettings.isEnabledLPr(s.info, flags)) { return PackageParser.generateServiceInfo(s, flags); } } @@ -1627,9 +1632,9 @@ class PackageManagerService extends IPackageManager.Stub { public ProviderInfo getProviderInfo(ComponentName component, int flags) { synchronized (mPackages) { PackageParser.Provider p = mProvidersByComponent.get(component); - if (Config.LOGV) Log.v( + if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getProviderInfo " + component + ": " + p); - if (p != null && mSettings.isEnabledLP(p.info, flags)) { + if (p != null && mSettings.isEnabledLPr(p.info, flags)) { return PackageParser.generateProviderInfo(p, flags); } } @@ -1693,7 +1698,7 @@ class PackageManagerService extends IPackageManager.Stub { public int checkUidPermission(String permName, int uid) { synchronized (mPackages) { - Object obj = mSettings.getUserIdLP(uid); + Object obj = mSettings.getUserIdLPr(uid); if (obj != null) { GrantedPermissions gp = (GrantedPermissions)obj; if (gp.grantedPermissions.contains(permName)) { @@ -1798,7 +1803,7 @@ class PackageManagerService extends IPackageManager.Stub { } if (changed) { if (!async) { - mSettings.writeLP(); + mSettings.writeLPr(); } else { scheduleWriteSettingsLocked(); } @@ -1829,7 +1834,7 @@ class PackageManagerService extends IPackageManager.Stub { + name); } mSettings.mPermissions.remove(name); - mSettings.writeLP(); + mSettings.writeLPr(); } } } @@ -1842,21 +1847,22 @@ class PackageManagerService extends IPackageManager.Stub { public int checkSignatures(String pkg1, String pkg2) { synchronized (mPackages) { - PackageParser.Package p1 = mPackages.get(pkg1); - PackageParser.Package p2 = mPackages.get(pkg2); + final PackageParser.Package p1 = mPackages.get(pkg1); + final PackageParser.Package p2 = mPackages.get(pkg2); if (p1 == null || p1.mExtras == null || p2 == null || p2.mExtras == null) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - return checkSignaturesLP(p1.mSignatures, p2.mSignatures); + return compareSignatures(p1.mSignatures, p2.mSignatures); } } public int checkUidSignatures(int uid1, int uid2) { + // reader synchronized (mPackages) { Signature[] s1; Signature[] s2; - Object obj = mSettings.getUserIdLP(uid1); + Object obj = mSettings.getUserIdLPr(uid1); if (obj != null) { if (obj instanceof SharedUserSetting) { s1 = ((SharedUserSetting)obj).signatures.mSignatures; @@ -1868,7 +1874,7 @@ class PackageManagerService extends IPackageManager.Stub { } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - obj = mSettings.getUserIdLP(uid2); + obj = mSettings.getUserIdLPr(uid2); if (obj != null) { if (obj instanceof SharedUserSetting) { s2 = ((SharedUserSetting)obj).signatures.mSignatures; @@ -1880,11 +1886,11 @@ class PackageManagerService extends IPackageManager.Stub { } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - return checkSignaturesLP(s1, s2); + return compareSignatures(s1, s2); } } - int checkSignaturesLP(Signature[] s1, Signature[] s2) { + static int compareSignatures(Signature[] s1, Signature[] s2) { if (s1 == null) { return s2 == null ? PackageManager.SIGNATURE_NEITHER_SIGNED @@ -1909,20 +1915,21 @@ class PackageManagerService extends IPackageManager.Stub { } public String[] getPackagesForUid(int uid) { + // reader synchronized (mPackages) { - Object obj = mSettings.getUserIdLP(uid); + Object obj = mSettings.getUserIdLPr(uid); if (obj instanceof SharedUserSetting) { - SharedUserSetting sus = (SharedUserSetting)obj; + final SharedUserSetting sus = (SharedUserSetting) obj; final int N = sus.packages.size(); - String[] res = new String[N]; - Iterator<PackageSetting> it = sus.packages.iterator(); - int i=0; + final String[] res = new String[N]; + final Iterator<PackageSetting> it = sus.packages.iterator(); + int i = 0; while (it.hasNext()) { res[i++] = it.next().name; } return res; } else if (obj instanceof PackageSetting) { - PackageSetting ps = (PackageSetting)obj; + final PackageSetting ps = (PackageSetting) obj; return new String[] { ps.name }; } } @@ -1930,13 +1937,14 @@ class PackageManagerService extends IPackageManager.Stub { } public String getNameForUid(int uid) { + // reader synchronized (mPackages) { - Object obj = mSettings.getUserIdLP(uid); + Object obj = mSettings.getUserIdLPr(uid); if (obj instanceof SharedUserSetting) { - SharedUserSetting sus = (SharedUserSetting)obj; + final SharedUserSetting sus = (SharedUserSetting) obj; return sus.name + ":" + sus.userId; } else if (obj instanceof PackageSetting) { - PackageSetting ps = (PackageSetting)obj; + final PackageSetting ps = (PackageSetting) obj; return ps.name; } } @@ -1947,8 +1955,9 @@ class PackageManagerService extends IPackageManager.Stub { if(sharedUserName == null) { return -1; } + // reader synchronized (mPackages) { - SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false); + final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false); if(suid == null) { return -1; } @@ -1973,11 +1982,9 @@ class PackageManagerService extends IPackageManager.Stub { // then let the user decide between them. ResolveInfo r0 = query.get(0); ResolveInfo r1 = query.get(1); - if (false) { - System.out.println(r0.activityInfo.name + - "=" + r0.priority + " vs " + - r1.activityInfo.name + - "=" + r1.priority); + if (DEBUG_INTENT_MATCHING) { + Log.d(TAG, r0.activityInfo.name + "=" + r0.priority + " vs " + + r1.activityInfo.name + "=" + r1.priority); } // If the first activity has a higher priority, or a different // default, then it is always desireable to pick it. @@ -2001,6 +2008,7 @@ class PackageManagerService extends IPackageManager.Stub { ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int priority) { + // writer synchronized (mPackages) { if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); List<PreferredActivity> prefs = @@ -2011,24 +2019,35 @@ class PackageManagerService extends IPackageManager.Stub { // We will only allow preferred activities that came // from the same match quality. int match = 0; + + if (DEBUG_PREFERRED) { + Log.v(TAG, "Figuring out best match..."); + } + final int N = query.size(); - if (DEBUG_PREFERRED) Log.v(TAG, "Figuring out best match..."); for (int j=0; j<N; j++) { - ResolveInfo ri = query.get(j); - if (DEBUG_PREFERRED) Log.v(TAG, "Match for " + ri.activityInfo - + ": 0x" + Integer.toHexString(match)); - if (ri.match > match) match = ri.match; + final ResolveInfo ri = query.get(j); + if (DEBUG_PREFERRED) { + Log.v(TAG, "Match for " + ri.activityInfo + ": 0x" + + Integer.toHexString(match)); + } + if (ri.match > match) { + match = ri.match; + } } - if (DEBUG_PREFERRED) Log.v(TAG, "Best match: 0x" - + Integer.toHexString(match)); + + if (DEBUG_PREFERRED) { + Log.v(TAG, "Best match: 0x" + Integer.toHexString(match)); + } + match &= IntentFilter.MATCH_CATEGORY_MASK; final int M = prefs.size(); for (int i=0; i<M; i++) { - PreferredActivity pa = prefs.get(i); + final PreferredActivity pa = prefs.get(i); if (pa.mPref.mMatch != match) { continue; } - ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags); + final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags); if (DEBUG_PREFERRED) { Log.v(TAG, "Got preferred activity:"); if (ai != null) { @@ -2039,7 +2058,7 @@ class PackageManagerService extends IPackageManager.Stub { } if (ai != null) { for (int j=0; j<N; j++) { - ResolveInfo ri = query.get(j); + final ResolveInfo ri = query.get(j); if (!ri.activityInfo.applicationInfo.packageName .equals(ai.applicationInfo.packageName)) { continue; @@ -2071,28 +2090,28 @@ class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags) { - ComponentName comp = intent.getComponent(); + final ComponentName comp = intent.getComponent(); if (comp != null) { - List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); - ActivityInfo ai = getActivityInfo(comp, flags); + final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); + final ActivityInfo ai = getActivityInfo(comp, flags); if (ai != null) { - ResolveInfo ri = new ResolveInfo(); + final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; list.add(ri); } return list; } + // reader synchronized (mPackages) { - String pkgName = intent.getPackage(); + final String pkgName = intent.getPackage(); if (pkgName == null) { - return (List<ResolveInfo>)mActivities.queryIntent(intent, - resolvedType, flags); + return mActivities.queryIntent(intent, resolvedType, flags); } - PackageParser.Package pkg = mPackages.get(pkgName); + final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { - return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent, - resolvedType, flags, pkg.activities); + return mActivities.queryIntentForPackage(intent, resolvedType, flags, + pkg.activities); } return new ArrayList<ResolveInfo>(); } @@ -2103,9 +2122,12 @@ class PackageManagerService extends IPackageManager.Stub { String resolvedType, int flags) { final String resultsAction = intent.getAction(); - List<ResolveInfo> results = queryIntentActivities( - intent, resolvedType, flags|PackageManager.GET_RESOLVED_FILTER); - if (Config.LOGV) Log.v(TAG, "Query " + intent + ": " + results); + List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags + | PackageManager.GET_RESOLVED_FILTER); + + if (DEBUG_INTENT_MATCHING) { + Log.v(TAG, "Query " + intent + ": " + results); + } int specificsPos = 0; int N; @@ -2125,16 +2147,21 @@ class PackageManagerService extends IPackageManager.Stub { continue; } - if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + sintent); + if (DEBUG_INTENT_MATCHING) { + Log.v(TAG, "Specific #" + i + ": " + sintent); + } + String action = sintent.getAction(); if (resultsAction != null && resultsAction.equals(action)) { // If this action was explicitly requested, then don't // remove things that have it. action = null; } - ComponentName comp = sintent.getComponent(); + ResolveInfo ri = null; ActivityInfo ai = null; + + ComponentName comp = sintent.getComponent(); if (comp == null) { ri = resolveIntent( sintent, @@ -2158,7 +2185,7 @@ class PackageManagerService extends IPackageManager.Stub { // Look for any generic query activities that are duplicates // of this specific one, and remove them from the results. - if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + ai); + if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Specific #" + i + ": " + ai); N = results.size(); int j; for (j=specificsPos; j<N; j++) { @@ -2168,7 +2195,7 @@ class PackageManagerService extends IPackageManager.Stub { comp.getPackageName())) || (action != null && sri.filter.matchAction(action))) { results.remove(j); - if (Config.LOGV) Log.v( + if (DEBUG_INTENT_MATCHING) Log.v( TAG, "Removing duplicate item from " + j + " due to specific " + specificsPos); if (ri == null) { @@ -2216,7 +2243,7 @@ class PackageManagerService extends IPackageManager.Stub { final ResolveInfo rij = results.get(j); if (rij.filter != null && rij.filter.hasAction(action)) { results.remove(j); - if (Config.LOGV) Log.v( + if (DEBUG_INTENT_MATCHING) Log.v( TAG, "Removing duplicate item from " + j + " due to action " + action + " at " + i); j--; @@ -2255,12 +2282,11 @@ class PackageManagerService extends IPackageManager.Stub { } } - if (Config.LOGV) Log.v(TAG, "Result: " + results); + if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Result: " + results); return results; } - public List<ResolveInfo> queryIntentReceivers(Intent intent, - String resolvedType, int flags) { + public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) { ComponentName comp = intent.getComponent(); if (comp != null) { List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); @@ -2273,25 +2299,22 @@ class PackageManagerService extends IPackageManager.Stub { return list; } + // reader synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { - return (List<ResolveInfo>)mReceivers.queryIntent(intent, - resolvedType, flags); + return mReceivers.queryIntent(intent, resolvedType, flags); } - PackageParser.Package pkg = mPackages.get(pkgName); + final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { - return (List<ResolveInfo>) mReceivers.queryIntentForPackage(intent, - resolvedType, flags, pkg.receivers); + return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers); } return null; } } - public ResolveInfo resolveService(Intent intent, String resolvedType, - int flags) { - List<ResolveInfo> query = queryIntentServices(intent, resolvedType, - flags); + public ResolveInfo resolveService(Intent intent, String resolvedType, int flags) { + List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags); if (query != null) { if (query.size() >= 1) { // If there is more than one service with the same priority, @@ -2302,56 +2325,54 @@ class PackageManagerService extends IPackageManager.Stub { return null; } - public List<ResolveInfo> queryIntentServices(Intent intent, - String resolvedType, int flags) { - ComponentName comp = intent.getComponent(); + public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags) { + final ComponentName comp = intent.getComponent(); if (comp != null) { - List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); - ServiceInfo si = getServiceInfo(comp, flags); + final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); + final ServiceInfo si = getServiceInfo(comp, flags); if (si != null) { - ResolveInfo ri = new ResolveInfo(); + final ResolveInfo ri = new ResolveInfo(); ri.serviceInfo = si; list.add(ri); } return list; } + // reader synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { - return (List<ResolveInfo>)mServices.queryIntent(intent, - resolvedType, flags); + return mServices.queryIntent(intent, resolvedType, flags); } - PackageParser.Package pkg = mPackages.get(pkgName); + final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { - return (List<ResolveInfo>)mServices.queryIntentForPackage(intent, - resolvedType, flags, pkg.services); + return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services); } return null; } } public List<PackageInfo> getInstalledPackages(int flags) { - ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>(); + final ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>(); + // writer synchronized (mPackages) { if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - Iterator<PackageSetting> i = mSettings.mPackages.values().iterator(); + final Iterator<PackageSetting> i = mSettings.mPackages.values().iterator(); while (i.hasNext()) { final PackageSetting ps = i.next(); - PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags); - if(psPkg != null) { + final PackageInfo psPkg = generatePackageInfoFromSettingsLPw(ps.name, flags); + if (psPkg != null) { finalList.add(psPkg); } } - } - else { - Iterator<PackageParser.Package> i = mPackages.values().iterator(); + } else { + final Iterator<PackageParser.Package> i = mPackages.values().iterator(); while (i.hasNext()) { final PackageParser.Package p = i.next(); if (p.applicationInfo != null) { - PackageInfo pi = generatePackageInfo(p, flags); - if(pi != null) { + final PackageInfo pi = generatePackageInfo(p, flags); + if (pi != null) { finalList.add(pi); } } @@ -2362,20 +2383,20 @@ class PackageManagerService extends IPackageManager.Stub { } public List<ApplicationInfo> getInstalledApplications(int flags) { - ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>(); + final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>(); + // writer synchronized(mPackages) { if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - Iterator<PackageSetting> i = mSettings.mPackages.values().iterator(); + final Iterator<PackageSetting> i = mSettings.mPackages.values().iterator(); while (i.hasNext()) { final PackageSetting ps = i.next(); - ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags); + ApplicationInfo ai = generateApplicationInfoFromSettingsLPw(ps.name, flags); if(ai != null) { finalList.add(ai); } } - } - else { - Iterator<PackageParser.Package> i = mPackages.values().iterator(); + } else { + final Iterator<PackageParser.Package> i = mPackages.values().iterator(); while (i.hasNext()) { final PackageParser.Package p = i.next(); if (p.applicationInfo != null) { @@ -2391,12 +2412,13 @@ class PackageManagerService extends IPackageManager.Stub { } public List<ApplicationInfo> getPersistentApplications(int flags) { - ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>(); + final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>(); + // reader synchronized (mPackages) { - Iterator<PackageParser.Package> i = mPackages.values().iterator(); + final Iterator<PackageParser.Package> i = mPackages.values().iterator(); while (i.hasNext()) { - PackageParser.Package p = i.next(); + final PackageParser.Package p = i.next(); if (p.applicationInfo != null && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 && (!mSafeMode || isSystemApp(p))) { @@ -2409,10 +2431,11 @@ class PackageManagerService extends IPackageManager.Stub { } public ProviderInfo resolveContentProvider(String name, int flags) { + // reader synchronized (mPackages) { final PackageParser.Provider provider = mProviders.get(name); return provider != null - && mSettings.isEnabledLP(provider.info, flags) + && mSettings.isEnabledLPr(provider.info, flags) && (!mSafeMode || (provider.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0) ? PackageParser.generateProviderInfo(provider, flags) @@ -2423,10 +2446,12 @@ class PackageManagerService extends IPackageManager.Stub { /** * @deprecated */ - public void querySyncProviders(List outNames, List outInfo) { + @Deprecated + public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) { + // reader synchronized (mPackages) { - Iterator<Map.Entry<String, PackageParser.Provider>> i - = mProviders.entrySet().iterator(); + final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet() + .iterator(); while (i.hasNext()) { Map.Entry<String, PackageParser.Provider> entry = i.next(); @@ -2446,22 +2471,22 @@ class PackageManagerService extends IPackageManager.Stub { int uid, int flags) { ArrayList<ProviderInfo> finalList = null; + // reader synchronized (mPackages) { - Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator(); + final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator(); while (i.hasNext()) { - PackageParser.Provider p = i.next(); + final PackageParser.Provider p = i.next(); if (p.info.authority != null - && (processName == null || - (p.info.processName.equals(processName) - && p.info.applicationInfo.uid == uid)) - && mSettings.isEnabledLP(p.info, flags) - && (!mSafeMode || (p.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0)) { + && (processName == null + || (p.info.processName.equals(processName) + && p.info.applicationInfo.uid == uid)) + && mSettings.isEnabledLPr(p.info, flags) + && (!mSafeMode + || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) { if (finalList == null) { finalList = new ArrayList<ProviderInfo>(3); } - finalList.add(PackageParser.generateProviderInfo(p, - flags)); + finalList.add(PackageParser.generateProviderInfo(p, flags)); } } } @@ -2475,6 +2500,7 @@ class PackageManagerService extends IPackageManager.Stub { public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) { + // reader synchronized (mPackages) { final PackageParser.Instrumentation i = mInstrumentation.get(name); return PackageParser.generateInstrumentationInfo(i, flags); @@ -2486,10 +2512,11 @@ class PackageManagerService extends IPackageManager.Stub { ArrayList<InstrumentationInfo> finalList = new ArrayList<InstrumentationInfo>(); + // reader synchronized (mPackages) { - Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator(); + final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator(); while (i.hasNext()) { - PackageParser.Instrumentation p = i.next(); + final PackageParser.Instrumentation p = i.next(); if (targetPackage == null || targetPackage.equals(p.info.targetPackage)) { finalList.add(PackageParser.generateInstrumentationInfo(p, @@ -2508,7 +2535,7 @@ class PackageManagerService extends IPackageManager.Stub { return; } - if (false) { + if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Scanning app dir " + dir); } @@ -2538,7 +2565,7 @@ class PackageManagerService extends IPackageManager.Stub { return fname; } - private static void reportSettingsProblem(int priority, String msg) { + static void reportSettingsProblem(int priority, String msg) { try { File fname = getSettingsProblemFile(); FileOutputStream out = new FileOutputStream(fname, true); @@ -2602,17 +2629,18 @@ class PackageManagerService extends IPackageManager.Stub { } PackageSetting ps = null; PackageSetting updatedPkg; + // reader synchronized (mPackages) { // Look to see if we already know about this package. String oldName = mSettings.mRenamedPackages.get(pkg.packageName); if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) { // This package has been renamed to its original name. Let's // use that. - ps = mSettings.peekPackageLP(oldName); + ps = mSettings.peekPackageLPr(oldName); } // If there was no original package, see one for the real package name. if (ps == null) { - ps = mSettings.peekPackageLP(pkg.packageName); + ps = mSettings.peekPackageLPr(pkg.packageName); } // Check to see if this package could be hiding/updating a system // package. Must look for it either under the original or real @@ -2641,6 +2669,7 @@ class PackageManagerService extends IPackageManager.Stub { // At this point, its safely assumed that package installation for // apps in system partition will go through. If not there won't be a working // version of the app + // writer synchronized (mPackages) { // Just remove the loaded entries from package lists. mPackages.remove(ps.name); @@ -2652,7 +2681,7 @@ class PackageManagerService extends IPackageManager.Stub { InstallArgs args = new FileInstallArgs(ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString); args.cleanUpResourcesLI(); - mSettings.enableSystemPackageLP(ps.name); + mSettings.enableSystemPackageLPw(ps.name); } } } @@ -2710,7 +2739,7 @@ class PackageManagerService extends IPackageManager.Stub { PackageParser.Package pkg) { if (pkgSetting.signatures.mSignatures != null) { // Already existing package. Make sure signatures match - if (checkSignaturesLP(pkgSetting.signatures.mSignatures, pkg.mSignatures) != + if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { Slog.e(TAG, "Package " + pkg.packageName + " signatures do not match the previously installed version; ignoring!"); @@ -2720,7 +2749,7 @@ class PackageManagerService extends IPackageManager.Stub { } // Check for shared user signatures if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) { - if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures, + if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { Slog.e(TAG, "Package " + pkg.packageName + " has no signatures that match those in shared user " @@ -2787,7 +2816,7 @@ class PackageManagerService extends IPackageManager.Stub { return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED; } - private boolean verifyPackageUpdate(PackageSetting oldPkg, PackageParser.Package newPkg) { + private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) { if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { Slog.w(TAG, "Unable to update from " + oldPkg.name + " to " + newPkg.packageName @@ -2861,8 +2890,11 @@ class PackageManagerService extends IPackageManager.Stub { } } - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) Log.d( - TAG, "Scanning package " + pkg.packageName); + if (DEBUG_PACKAGE_SCANNING) { + if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + Log.d(TAG, "Scanning package " + pkg.packageName); + } + if (mPackages.containsKey(pkg.packageName) || mSharedLibraries.containsKey(pkg.packageName)) { Slog.w(TAG, "Application package " + pkg.packageName @@ -2885,6 +2917,7 @@ class PackageManagerService extends IPackageManager.Stub { pkg.mAdoptPermissions = null; } + // writer synchronized (mPackages) { // Check all shared libraries and map to their actual file path. if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) { @@ -2895,7 +2928,7 @@ class PackageManagerService extends IPackageManager.Stub { int num = 0; int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0; for (int i=0; i<N; i++) { - String file = mSharedLibraries.get(pkg.usesLibraries.get(i)); + final String file = mSharedLibraries.get(pkg.usesLibraries.get(i)); if (file == null) { Slog.e(TAG, "Package " + pkg.packageName + " requires unavailable shared library " @@ -2908,7 +2941,7 @@ class PackageManagerService extends IPackageManager.Stub { } N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0; for (int i=0; i<N; i++) { - String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i)); + final String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i)); if (file == null) { Slog.w(TAG, "Package " + pkg.packageName + " desires unavailable shared library " @@ -2926,7 +2959,7 @@ class PackageManagerService extends IPackageManager.Stub { } if (pkg.mSharedUserId != null) { - suid = mSettings.getSharedUserLP(pkg.mSharedUserId, + suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, pkg.applicationInfo.flags, true); if (suid == null) { Slog.w(TAG, "Creating application package " + pkg.packageName @@ -2934,18 +2967,10 @@ class PackageManagerService extends IPackageManager.Stub { mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; return null; } - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) { - Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" - + suid.userId + "): packages=" + suid.packages); - } - } - - if (false) { - if (pkg.mOriginalPackages != null) { - Log.w(TAG, "WAITING FOR DEBUGGER"); - Debug.waitForDebugger(); - Log.i(TAG, "Package " + pkg.packageName + " from original packages" - + pkg.mOriginalPackages); + if (DEBUG_PACKAGE_SCANNING) { + if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId + + "): packages=" + suid.packages); } } @@ -2955,7 +2980,7 @@ class PackageManagerService extends IPackageManager.Stub { if (pkg.mOriginalPackages != null) { // This package may need to be renamed to a previously // installed name. Let's check on that... - String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage); + final String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage); if (pkg.mOriginalPackages.contains(renamed)) { // This package had originally been installed as the // original name, and we have already taken care of @@ -2971,11 +2996,11 @@ class PackageManagerService extends IPackageManager.Stub { } else { for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) { - if ((origPackage=mSettings.peekPackageLP( + if ((origPackage = mSettings.peekPackageLPr( pkg.mOriginalPackages.get(i))) != null) { // We do have the package already installed under its // original name... should we use it? - if (!verifyPackageUpdate(origPackage, pkg)) { + if (!verifyPackageUpdateLPr(origPackage, pkg)) { // New package is not compatible with original. origPackage = null; continue; @@ -3006,7 +3031,7 @@ class PackageManagerService extends IPackageManager.Stub { // Just create the setting, don't add it yet. For already existing packages // the PkgSetting exists already and doesn't have to be created. - pkgSetting = mSettings.getPackageLP(pkg, origPackage, realName, suid, destCodeFile, + pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.flags, true, false); if (pkgSetting == null) { @@ -3059,7 +3084,7 @@ class PackageManagerService extends IPackageManager.Stub { // associated with an overall shared user, which doesn't seem all // that unreasonable. if (pkgSetting.sharedUser != null) { - if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures, + if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser); mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; @@ -3077,7 +3102,7 @@ class PackageManagerService extends IPackageManager.Stub { // package isn't already installed, since we don't want to break // things that are installed. if ((scanMode&SCAN_NEW_INSTALL) != 0) { - int N = pkg.providers.size(); + final int N = pkg.providers.size(); int i; for (i=0; i<N; i++) { PackageParser.Provider p = pkg.providers.get(i); @@ -3098,29 +3123,28 @@ class PackageManagerService extends IPackageManager.Stub { } } } - } - final String pkgName = pkg.packageName; - - if (pkg.mAdoptPermissions != null) { - // This package wants to adopt ownership of permissions from - // another package. - for (int i=pkg.mAdoptPermissions.size()-1; i>=0; i--) { - String origName = pkg.mAdoptPermissions.get(i); - PackageSetting orig = mSettings.peekPackageLP(origName); - if (orig != null) { - if (verifyPackageUpdate(orig, pkg)) { - Slog.i(TAG, "Adopting permissions from " - + origName + " to " + pkg.packageName); - mSettings.transferPermissions(origName, pkg.packageName); + if (pkg.mAdoptPermissions != null) { + // This package wants to adopt ownership of permissions from + // another package. + for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) { + final String origName = pkg.mAdoptPermissions.get(i); + final PackageSetting orig = mSettings.peekPackageLPr(origName); + if (orig != null) { + if (verifyPackageUpdateLPr(orig, pkg)) { + Slog.i(TAG, "Adopting permissions from " + origName + " to " + + pkg.packageName); + mSettings.transferPermissionsLPw(origName, pkg.packageName); + } } } } } + + final String pkgName = pkg.packageName; final long scanFileTime = scanFile.lastModified(); final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0; - final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp; pkg.applicationInfo.processName = fixProcessName( pkg.applicationInfo.packageName, pkg.applicationInfo.processName, @@ -3185,6 +3209,7 @@ class PackageManagerService extends IPackageManager.Stub { + " has mismatched uid: " + mOutPermissions[1] + " on disk, " + pkg.applicationInfo.uid + " in settings"; + // writer synchronized (mPackages) { mSettings.mReadMessages.append(msg); mSettings.mReadMessages.append('\n'); @@ -3197,8 +3222,10 @@ class PackageManagerService extends IPackageManager.Stub { } pkg.applicationInfo.dataDir = dataPath.getPath(); } else { - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGV) - Log.v(TAG, "Want this data dir: " + dataPath); + if (DEBUG_PACKAGE_SCANNING) { + if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + Log.v(TAG, "Want this data dir: " + dataPath); + } //invoke installer to do the actual installation if (mInstaller != null) { int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid, @@ -3316,13 +3343,14 @@ class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.uid); } + // writer synchronized (mPackages) { // We don't expect installation to fail beyond this point, if ((scanMode&SCAN_MONITOR) != 0) { mAppDirs.put(pkg.mPath, pkg); } // Add the new setting to mSettings - mSettings.insertPackageSettingLP(pkgSetting, pkg); + mSettings.insertPackageSettingLPw(pkgSetting, pkg); // Add the new setting to mPackages mPackages.put(pkg.applicationInfo.packageName, pkg); // Make sure we don't accidentally delete its data. @@ -3378,10 +3406,12 @@ class PackageManagerService extends IPackageManager.Stub { } else { p.info.authority = p.info.authority + ";" + names[j]; } - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) - Log.d(TAG, "Registered content provider: " + names[j] + - ", className = " + p.info.name + - ", isSyncable = " + p.info.isSyncable); + if (DEBUG_PACKAGE_SCANNING) { + if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + Log.d(TAG, "Registered content provider: " + names[j] + + ", className = " + p.info.name + ", isSyncable = " + + p.info.isSyncable); + } } else { PackageParser.Provider other = mProviders.get(names[j]); Slog.w(TAG, "Skipping provider name " + names[j] + @@ -3402,7 +3432,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Providers: " + r); + if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r); } N = pkg.services.size(); @@ -3422,7 +3452,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Services: " + r); + if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r); } N = pkg.receivers.size(); @@ -3442,7 +3472,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Receivers: " + r); + if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r); } N = pkg.activities.size(); @@ -3462,7 +3492,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Activities: " + r); + if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r); } N = pkg.permissionGroups.size(); @@ -3496,7 +3526,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Permission Groups: " + r); + if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permission Groups: " + r); } N = pkg.permissions.size(); @@ -3561,7 +3591,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Permissions: " + r); + if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permissions: " + r); } N = pkg.instrumentation.size(); @@ -3584,7 +3614,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r); + if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r); } if (pkg.protectedBroadcasts != null) { @@ -3613,25 +3643,15 @@ class PackageManagerService extends IPackageManager.Stub { } } - // Return the path of the directory that will contain the native binaries - // of a given installed package. This is relative to the data path. - // - private File getNativeBinaryDirForPackage(PackageParser.Package pkg) { - final String nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; - if (nativeLibraryDir != null) { - return new File(nativeLibraryDir); - } else { - // Fall back for old packages - return new File(pkg.applicationInfo.dataDir, LIB_DIR_NAME); - } - } - void removePackageLI(PackageParser.Package pkg, boolean chatty) { - if (chatty && Config.LOGD) Log.d( - TAG, "Removing package " + pkg.applicationInfo.packageName ); + if (DEBUG_INSTALL) { + if (chatty) + Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName); + } + // writer synchronized (mPackages) { - clearPackagePreferredActivitiesLP(pkg.packageName); + clearPackagePreferredActivitiesLPw(pkg.packageName); mPackages.remove(pkg.applicationInfo.packageName); if (pkg.mPath != null) { @@ -3657,10 +3677,12 @@ class PackageManagerService extends IPackageManager.Stub { for (int j = 0; j < names.length; j++) { if (mProviders.get(names[j]) == p) { mProviders.remove(names[j]); - if (chatty && Config.LOGD) Log.d( - TAG, "Unregistered content provider: " + names[j] + - ", className = " + p.info.name + - ", isSyncable = " + p.info.isSyncable); + if (DEBUG_REMOVE) { + if (chatty) + Log.d(TAG, "Unregistered content provider: " + names[j] + + ", className = " + p.info.name + ", isSyncable = " + + p.info.isSyncable); + } } } if (chatty) { @@ -3673,7 +3695,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Providers: " + r); + if (DEBUG_REMOVE) Log.d(TAG, " Providers: " + r); } N = pkg.services.size(); @@ -3691,7 +3713,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Services: " + r); + if (DEBUG_REMOVE) Log.d(TAG, " Services: " + r); } N = pkg.receivers.size(); @@ -3709,7 +3731,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Receivers: " + r); + if (DEBUG_REMOVE) Log.d(TAG, " Receivers: " + r); } N = pkg.activities.size(); @@ -3727,17 +3749,15 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Activities: " + r); + if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r); } N = pkg.permissions.size(); r = null; for (i=0; i<N; i++) { PackageParser.Permission p = pkg.permissions.get(i); - boolean tree = false; BasePermission bp = mSettings.mPermissions.get(p.info.name); if (bp == null) { - tree = true; bp = mSettings.mPermissionTrees.get(p.info.name); } if (bp != null && bp.perm == p) { @@ -3753,7 +3773,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Permissions: " + r); + if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); } N = pkg.instrumentation.size(); @@ -3771,7 +3791,7 @@ class PackageManagerService extends IPackageManager.Stub { } } if (r != null) { - if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r); + if (DEBUG_REMOVE) Log.d(TAG, " Instrumentation: " + r); } } } @@ -3789,14 +3809,13 @@ class PackageManagerService extends IPackageManager.Stub { return false; } - private void updatePermissionsLP(String changingPkg, + private void updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo, boolean grantPermissions, boolean replace, boolean replaceAll) { // Make sure there are no dangling permission trees. - Iterator<BasePermission> it = mSettings.mPermissionTrees - .values().iterator(); + Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator(); while (it.hasNext()) { - BasePermission bp = it.next(); + final BasePermission bp = it.next(); if (bp.packageSetting == null) { // We may not yet have parsed the package, so just see if // we still know about its settings. @@ -3820,13 +3839,13 @@ class PackageManagerService extends IPackageManager.Stub { // and make sure there are no dangling permissions. it = mSettings.mPermissions.values().iterator(); while (it.hasNext()) { - BasePermission bp = it.next(); + final BasePermission bp = it.next(); if (bp.type == BasePermission.TYPE_DYNAMIC) { if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name=" + bp.name + " pkg=" + bp.sourcePackage + " info=" + bp.pendingInfo); if (bp.packageSetting == null && bp.pendingInfo != null) { - BasePermission tree = findPermissionTreeLP(bp.name); + final BasePermission tree = findPermissionTreeLP(bp.name); if (tree != null) { bp.packageSetting = tree.packageSetting; bp.perm = new PackageParser.Permission(tree.perm.owner, @@ -3861,18 +3880,18 @@ class PackageManagerService extends IPackageManager.Stub { if (grantPermissions) { for (PackageParser.Package pkg : mPackages.values()) { if (pkg != pkgInfo) { - grantPermissionsLP(pkg, replaceAll); + grantPermissionsLPw(pkg, replaceAll); } } } if (pkgInfo != null) { - grantPermissionsLP(pkgInfo, replace); + grantPermissionsLPw(pkgInfo, replace); } } - private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) { - final PackageSetting ps = (PackageSetting)pkg.mExtras; + private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace) { + final PackageSetting ps = (PackageSetting) pkg.mExtras; if (ps == null) { return; } @@ -3893,12 +3912,11 @@ class PackageManagerService extends IPackageManager.Stub { final int N = pkg.requestedPermissions.size(); for (int i=0; i<N; i++) { - String name = pkg.requestedPermissions.get(i); - BasePermission bp = mSettings.mPermissions.get(name); - if (false) { + final String name = pkg.requestedPermissions.get(i); + final BasePermission bp = mSettings.mPermissions.get(name); + if (DEBUG_INSTALL) { if (gp != ps) { - Log.i(TAG, "Package " + pkg.packageName + " checking " + name - + ": " + bp); + Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp); } } if (bp != null && bp.packageSetting != null) { @@ -3913,10 +3931,10 @@ class PackageManagerService extends IPackageManager.Stub { allowed = false; } else if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE || bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { - allowed = (checkSignaturesLP( + allowed = (compareSignatures( bp.packageSetting.signatures.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH) - || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures) + || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH); if (!allowed && bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { @@ -3924,8 +3942,8 @@ class PackageManagerService extends IPackageManager.Stub { // For updated system applications, the signatureOrSystem permission // is granted only if it had been defined by the original application. if (isUpdatedSystemApp(pkg)) { - PackageSetting sysPs = mSettings.getDisabledSystemPkg( - pkg.packageName); + final PackageSetting sysPs = mSettings + .getDisabledSystemPkgLPr(pkg.packageName); final GrantedPermissions origGp = sysPs.sharedUser != null ? sysPs.sharedUser : sysPs; if (origGp.grantedPermissions.contains(perm)) { @@ -3944,7 +3962,7 @@ class PackageManagerService extends IPackageManager.Stub { } else { allowed = false; } - if (false) { + if (DEBUG_INSTALL) { if (gp != ps) { Log.i(TAG, "Package " + pkg.packageName + " granting " + perm); } @@ -4022,25 +4040,26 @@ class PackageManagerService extends IPackageManager.Stub { private final class ActivityIntentResolver extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { - public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) { + public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, + boolean defaultOnly) { mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; return super.queryIntent(intent, resolvedType, defaultOnly); } - public List queryIntent(Intent intent, String resolvedType, int flags) { + public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) { mFlags = flags; return super.queryIntent(intent, resolvedType, (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); } - public List queryIntentForPackage(Intent intent, String resolvedType, int flags, - ArrayList<PackageParser.Activity> packageActivities) { + public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, + int flags, ArrayList<PackageParser.Activity> packageActivities) { if (packageActivities == null) { return null; } mFlags = flags; final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0; - int N = packageActivities.size(); + final int N = packageActivities.size(); ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut = new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N); @@ -4057,11 +4076,13 @@ class PackageManagerService extends IPackageManager.Stub { public final void addActivity(PackageParser.Activity a, String type) { final boolean systemApp = isSystemApp(a.info.applicationInfo); mActivities.put(a.getComponentName(), a); - if (SHOW_INFO || Config.LOGV) Log.v( + if (DEBUG_SHOW_INFO) + Log.v( TAG, " " + type + " " + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":"); - if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name); - int NI = a.intents.size(); + if (DEBUG_SHOW_INFO) + Log.v(TAG, " Class=" + a.info.name); + final int NI = a.intents.size(); for (int j=0; j<NI; j++) { PackageParser.ActivityIntentInfo intent = a.intents.get(j); if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) { @@ -4069,7 +4090,7 @@ class PackageManagerService extends IPackageManager.Stub { Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity " + a.className + " with priority > 0, forcing to 0"); } - if (SHOW_INFO || Config.LOGV) { + if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } @@ -4082,14 +4103,16 @@ class PackageManagerService extends IPackageManager.Stub { public final void removeActivity(PackageParser.Activity a, String type) { mActivities.remove(a.getComponentName()); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " " + type + " " + - (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":"); - if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name); - int NI = a.intents.size(); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + type + " " + + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel + : a.info.name) + ":"); + Log.v(TAG, " Class=" + a.info.name); + } + final int NI = a.intents.size(); for (int j=0; j<NI; j++) { PackageParser.ActivityIntentInfo intent = a.intents.get(j); - if (SHOW_INFO || Config.LOGV) { + if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } @@ -4131,7 +4154,7 @@ class PackageManagerService extends IPackageManager.Stub { @Override protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, int match) { - if (!mSettings.isEnabledLP(info.activity.info, mFlags)) { + if (!mSettings.isEnabledLPr(info.activity.info, mFlags)) { return null; } final PackageParser.Activity activity = info.activity; @@ -4193,25 +4216,26 @@ class PackageManagerService extends IPackageManager.Stub { private final class ServiceIntentResolver extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> { - public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) { + public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, + boolean defaultOnly) { mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; return super.queryIntent(intent, resolvedType, defaultOnly); } - public List queryIntent(Intent intent, String resolvedType, int flags) { + public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) { mFlags = flags; return super.queryIntent(intent, resolvedType, (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); } - public List queryIntentForPackage(Intent intent, String resolvedType, int flags, - ArrayList<PackageParser.Service> packageServices) { + public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, + int flags, ArrayList<PackageParser.Service> packageServices) { if (packageServices == null) { return null; } mFlags = flags; final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0; - int N = packageServices.size(); + final int N = packageServices.size(); ArrayList<ArrayList<PackageParser.ServiceIntentInfo>> listCut = new ArrayList<ArrayList<PackageParser.ServiceIntentInfo>>(N); @@ -4227,16 +4251,17 @@ class PackageManagerService extends IPackageManager.Stub { public final void addService(PackageParser.Service s) { mServices.put(s.getComponentName(), s); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " " + (s.info.nonLocalizedLabel != null + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + + (s.info.nonLocalizedLabel != null ? s.info.nonLocalizedLabel : s.info.name) + ":"); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " Class=" + s.info.name); - int NI = s.intents.size(); + Log.v(TAG, " Class=" + s.info.name); + } + final int NI = s.intents.size(); int j; for (j=0; j<NI; j++) { PackageParser.ServiceIntentInfo intent = s.intents.get(j); - if (SHOW_INFO || Config.LOGV) { + if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } @@ -4249,16 +4274,16 @@ class PackageManagerService extends IPackageManager.Stub { public final void removeService(PackageParser.Service s) { mServices.remove(s.getComponentName()); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " " + (s.info.nonLocalizedLabel != null + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + (s.info.nonLocalizedLabel != null ? s.info.nonLocalizedLabel : s.info.name) + ":"); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " Class=" + s.info.name); - int NI = s.intents.size(); + Log.v(TAG, " Class=" + s.info.name); + } + final int NI = s.intents.size(); int j; for (j=0; j<NI; j++) { PackageParser.ServiceIntentInfo intent = s.intents.get(j); - if (SHOW_INFO || Config.LOGV) { + if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } @@ -4301,7 +4326,7 @@ class PackageManagerService extends IPackageManager.Stub { protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, int match) { final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter; - if (!mSettings.isEnabledLP(info.service.info, mFlags)) { + if (!mSettings.isEnabledLPr(info.service.info, mFlags)) { return null; } final PackageParser.Service service = info.service; @@ -4394,7 +4419,7 @@ class PackageManagerService extends IPackageManager.Stub { } }; - private static final void sendPackageBroadcast(String action, String pkg, + static final void sendPackageBroadcast(String action, String pkg, Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { @@ -4425,6 +4450,7 @@ class PackageManagerService extends IPackageManager.Stub { } public String nextPackageToClean(String lastPackage) { + // writer synchronized (mPackages) { if (!isExternalMediaAvailable()) { // If the external storage is no longer mounted at this point, @@ -4445,6 +4471,7 @@ class PackageManagerService extends IPackageManager.Stub { } void startCleaningPackages() { + // reader synchronized (mPackages) { if (!isExternalMediaAvailable()) { return; @@ -4477,6 +4504,7 @@ class PackageManagerService extends IPackageManager.Stub { String addedPackage = null; int addedUid = -1; + // TODO post a message to the handler to obtain serial ordering synchronized (mInstallLock) { String fullPathStr = null; File fullPath = null; @@ -4485,13 +4513,12 @@ class PackageManagerService extends IPackageManager.Stub { fullPathStr = fullPath.getPath(); } - if (Config.LOGV) Log.v( - TAG, "File " + fullPathStr + " changed: " - + Integer.toHexString(event)); + if (DEBUG_APP_DIR_OBSERVER) + Log.v(TAG, "File " + fullPathStr + " changed: " + Integer.toHexString(event)); if (!isPackageFilename(path)) { - if (Config.LOGV) Log.v( - TAG, "Ignoring change of non-package file: " + fullPathStr); + if (DEBUG_APP_DIR_OBSERVER) + Log.v(TAG, "Ignoring change of non-package file: " + fullPathStr); return; } @@ -4501,6 +4528,7 @@ class PackageManagerService extends IPackageManager.Stub { return; } PackageParser.Package p = null; + // reader synchronized (mPackages) { p = mAppDirs.get(fullPathStr); } @@ -4522,8 +4550,14 @@ class PackageManagerService extends IPackageManager.Stub { SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME, System.currentTimeMillis()); if (p != null) { + /* + * TODO this seems dangerous as the package may have + * changed since we last acquired the mPackages + * lock. + */ + // writer synchronized (mPackages) { - updatePermissionsLP(p.packageName, p, + updatePermissionsLPw(p.packageName, p, p.permissions.size() > 0, false, false); } addedPackage = p.applicationInfo.packageName; @@ -4532,8 +4566,9 @@ class PackageManagerService extends IPackageManager.Stub { } } + // reader synchronized (mPackages) { - mSettings.writeLP(); + mSettings.writeLPr(); } } @@ -4581,13 +4616,9 @@ class PackageManagerService extends IPackageManager.Stub { mHandler.sendMessage(msg); } - public void setInstallerPackageName(String targetPackage, - String installerPackageName) { - PackageSetting pkgSetting; + public void setInstallerPackageName(String targetPackage, String installerPackageName) { final int uid = Binder.getCallingUid(); - final int permission = mContext.checkCallingPermission( - android.Manifest.permission.INSTALL_PACKAGES); - final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); + // writer synchronized (mPackages) { PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage); if (targetPackageSetting == null) { @@ -4606,7 +4637,7 @@ class PackageManagerService extends IPackageManager.Stub { } Signature[] callerSignature; - Object obj = mSettings.getUserIdLP(uid); + Object obj = mSettings.getUserIdLPr(uid); if (obj != null) { if (obj instanceof SharedUserSetting) { callerSignature = ((SharedUserSetting)obj).signatures.mSignatures; @@ -4622,7 +4653,7 @@ class PackageManagerService extends IPackageManager.Stub { // Verify: can't set installerPackageName to a package that is // not signed with the same cert as the caller. if (installerPackageSetting != null) { - if (checkSignaturesLP(callerSignature, + if (compareSignatures(callerSignature, installerPackageSetting.signatures.mSignatures) != PackageManager.SIGNATURE_MATCH) { throw new SecurityException( @@ -4639,7 +4670,7 @@ class PackageManagerService extends IPackageManager.Stub { // If the currently set package isn't valid, then it's always // okay to change it. if (setting != null) { - if (checkSignaturesLP(callerSignature, + if (compareSignatures(callerSignature, setting.signatures.mSignatures) != PackageManager.SIGNATURE_MATCH) { throw new SecurityException( @@ -4855,6 +4886,7 @@ class PackageManagerService extends IPackageManager.Stub { String packageName = pkgLite.packageName; int installLocation = pkgLite.installLocation; boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0; + // reader synchronized (mPackages) { PackageParser.Package pkg = mPackages.get(packageName); if (pkg != null) { @@ -4919,12 +4951,24 @@ class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Cannot install fwd locked apps on sdcard"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { + final long lowThreshold; + + final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager + .getService(DeviceStorageMonitorService.SERVICE); + if (dsm == null) { + Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed"); + lowThreshold = 0L; + } else { + lowThreshold = dsm.getMemoryLowThreshold(); + } + // Remote call to find out default install location final PackageInfoLite pkgLite; try { mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); - pkgLite = mContainerService.getMinimalPackageInfo(packageURI, flags); + pkgLite = mContainerService.getMinimalPackageInfo(packageURI, flags, + lowThreshold); } finally { mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); } @@ -5144,10 +5188,26 @@ class PackageManagerService extends IPackageManager.Stub { } boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { + final long lowThreshold; + + final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager + .getService(DeviceStorageMonitorService.SERVICE); + if (dsm == null) { + Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed"); + lowThreshold = 0L; + } else { + if (dsm.isMemoryLow()) { + Log.w(TAG, "Memory is reported as being too low; aborting package install"); + return false; + } + + lowThreshold = dsm.getMemoryLowThreshold(); + } + try { mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); - return imcs.checkFreeStorage(false, packageURI); + return imcs.checkInternalFreeStorage(packageURI, lowThreshold); } finally { mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); } @@ -5373,7 +5433,7 @@ class PackageManagerService extends IPackageManager.Stub { try { mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); - return imcs.checkFreeStorage(true, packageURI); + return imcs.checkExternalFreeStorage(packageURI); } finally { mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION); } @@ -5697,7 +5757,7 @@ class PackageManagerService extends IPackageManager.Stub { // First find the old package info and check signatures synchronized(mPackages) { oldPackage = mPackages.get(pkgName); - if (checkSignaturesLP(oldPackage.mSignatures, pkg.mSignatures) + if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; return; @@ -5720,11 +5780,6 @@ class PackageManagerService extends IPackageManager.Stub { boolean deletedPkg = true; boolean updatedSettings = false; - String oldInstallerPackageName = null; - synchronized (mPackages) { - oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName); - } - long origUpdateTime; if (pkg.mExtras != null) { origUpdateTime = ((PackageSetting)pkg.mExtras).lastUpdateTime; @@ -5788,10 +5843,12 @@ class PackageManagerService extends IPackageManager.Stub { return; } // Restore of old package succeeded. Update permissions. + // writer synchronized (mPackages) { - updatePermissionsLP(deletedPackage.packageName, deletedPackage, + updatePermissionsLPw(deletedPackage.packageName, deletedPackage, true, false, false); - mSettings.writeLP(); + // can downgrade to reader + mSettings.writeLPr(); } Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade"); } @@ -5814,6 +5871,7 @@ class PackageManagerService extends IPackageManager.Stub { } PackageParser.Package oldPkg; PackageSetting oldPkgSetting; + // reader synchronized (mPackages) { oldPkg = mPackages.get(packageName); oldPkgSetting = mSettings.mPackages.get(packageName); @@ -5830,8 +5888,9 @@ class PackageManagerService extends IPackageManager.Stub { res.removedInfo.removedPackage = packageName; // Remove existing system package removePackageLI(oldPkg, true); + // writer synchronized (mPackages) { - if (!mSettings.disableSystemPackageLP(packageName) && deletedPackage != null) { + if (!mSettings.disableSystemPackageLPw(packageName) && deletedPackage != null) { // We didn't need to disable the .apk as a current system package, // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. @@ -5875,11 +5934,11 @@ class PackageManagerService extends IPackageManager.Stub { // Restore the old system information in Settings synchronized(mPackages) { if (updatedSettings) { - mSettings.enableSystemPackageLP(packageName); + mSettings.enableSystemPackageLPw(packageName); mSettings.setInstallerPackageName(packageName, oldPkgSetting.installerPackageName); } - mSettings.writeLP(); + mSettings.writeLPr(); } } } @@ -5913,8 +5972,8 @@ class PackageManagerService extends IPackageManager.Stub { //write settings. the installStatus will be incomplete at this stage. //note that the new package setting would have already been //added to mPackages. It hasn't been persisted yet. - mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE); - mSettings.writeLP(); + mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE); + mSettings.writeLPr(); } if ((res.returnCode = moveDexFilesLI(newPackage)) @@ -5932,16 +5991,16 @@ class PackageManagerService extends IPackageManager.Stub { Log.d(TAG, "New package installed in " + newPackage.mPath); } synchronized (mPackages) { - updatePermissionsLP(newPackage.packageName, newPackage, + updatePermissionsLPw(newPackage.packageName, newPackage, newPackage.permissions.size() > 0, true, false); res.name = pkgName; res.uid = newPackage.applicationInfo.uid; res.pkg = newPackage; - mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE); + mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE); mSettings.setInstallerPackageName(pkgName, installerPackageName); res.returnCode = PackageManager.INSTALL_SUCCEEDED; //to update install status - mSettings.writeLP(); + mSettings.writeLPr(); } } @@ -6040,7 +6099,6 @@ class PackageManagerService extends IPackageManager.Stub { } private int setPermissionsLI(PackageParser.Package newPackage) { - String pkgName = newPackage.packageName; int retCode = 0; // TODO Gross hack but fix later. Ideally move this to be a post installation // check after alloting uid. @@ -6070,9 +6128,8 @@ class PackageManagerService extends IPackageManager.Stub { } if (retCode != 0) { - Slog.e(TAG, "Couldn't set new package file permissions for " + - newPackage.mPath - + ". The return code was: " + retCode); + Slog.e(TAG, "Couldn't set new package file permissions for " + newPackage.mPath + + ". The return code was: " + retCode); // TODO Define new internal error return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } @@ -6321,7 +6378,8 @@ class PackageManagerService extends IPackageManager.Stub { } removePackageLI(p, (flags&REMOVE_CHATTY) != 0); // Retrieve object to delete permissions for shared user later on - PackageSetting deletedPs; + final PackageSetting deletedPs; + // reader synchronized (mPackages) { deletedPs = mSettings.mPackages.get(packageName); } @@ -6335,23 +6393,28 @@ class PackageManagerService extends IPackageManager.Stub { } } else { // for simulator - PackageParser.Package pkg = mPackages.get(packageName); - File dataDir = new File(pkg.applicationInfo.dataDir); + File dataDir; + // reader + synchronized (mPackages) { + PackageParser.Package pkg = mPackages.get(packageName); + dataDir = new File(pkg.applicationInfo.dataDir); + } dataDir.delete(); } schedulePackageCleaning(packageName); } + // writer synchronized (mPackages) { if (deletedPs != null) { if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { if (outInfo != null) { - outInfo.removedUid = mSettings.removePackageLP(packageName); + outInfo.removedUid = mSettings.removePackageLPw(packageName); } if (deletedPs != null) { - updatePermissionsLP(deletedPs.name, null, false, false, false); + updatePermissionsLPw(deletedPs.name, null, false, false, false); if (deletedPs.sharedUser != null) { // remove permissions associated with package - mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids); + mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids); } } } @@ -6366,9 +6429,10 @@ class PackageManagerService extends IPackageManager.Stub { mSettings.mPreferredActivities.removeFilter(pa); } } + // can downgrade to reader if (writeSettings) { // Save settings now - mSettings.writeLP(); + mSettings.writeLPr(); } } } @@ -6388,8 +6452,9 @@ class PackageManagerService extends IPackageManager.Stub { // Confirm if the system package has been updated // An updated system app can be deleted. This will also have to restore // the system pkg from system partition + // reader synchronized (mPackages) { - ps = mSettings.getDisabledSystemPkg(p.packageName); + ps = mSettings.getDisabledSystemPkgLPr(p.packageName); } if (ps == null) { Slog.w(TAG, "Attempt to delete unknown system package "+ p.packageName); @@ -6411,9 +6476,10 @@ class PackageManagerService extends IPackageManager.Stub { if (!ret) { return false; } + // writer synchronized (mPackages) { // Reinstate the old system package - mSettings.enableSystemPackageLP(p.packageName); + mSettings.enableSystemPackageLPw(p.packageName); // Remove any native libraries from the upgraded package. NativeLibraryHelper.removeNativeBinariesLI(p.applicationInfo.nativeLibraryDir); } @@ -6426,10 +6492,12 @@ class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError); return false; } + // writer synchronized (mPackages) { - updatePermissionsLP(newPkg.packageName, newPkg, true, true, false); + updatePermissionsLPw(newPkg.packageName, newPkg, true, true, false); + // can downgrade to reader here if (writeSettings) { - mSettings.writeLP(); + mSettings.writeLPr(); } } return true; @@ -6717,16 +6785,14 @@ class PackageManagerService extends IPackageManager.Stub { return new ArrayList<PackageInfo>(); } - int getUidTargetSdkVersionLockedLP(int uid) { - Object obj = mSettings.getUserIdLP(uid); + private int getUidTargetSdkVersionLockedLPr(int uid) { + Object obj = mSettings.getUserIdLPr(uid); if (obj instanceof SharedUserSetting) { - SharedUserSetting sus = (SharedUserSetting)obj; - final int N = sus.packages.size(); + final SharedUserSetting sus = (SharedUserSetting) obj; int vers = Build.VERSION_CODES.CUR_DEVELOPMENT; - Iterator<PackageSetting> it = sus.packages.iterator(); - int i=0; + final Iterator<PackageSetting> it = sus.packages.iterator(); while (it.hasNext()) { - PackageSetting ps = it.next(); + final PackageSetting ps = it.next(); if (ps.pkg != null) { int v = ps.pkg.applicationInfo.targetSdkVersion; if (v < vers) vers = v; @@ -6734,7 +6800,7 @@ class PackageManagerService extends IPackageManager.Stub { } return vers; } else if (obj instanceof PackageSetting) { - PackageSetting ps = (PackageSetting)obj; + final PackageSetting ps = (PackageSetting) obj; if (ps.pkg != null) { return ps.pkg.applicationInfo.targetSdkVersion; } @@ -6744,11 +6810,12 @@ class PackageManagerService extends IPackageManager.Stub { public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) { + // writer synchronized (mPackages) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) != PackageManager.PERMISSION_GRANTED) { - if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid()) + if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid()) < Build.VERSION_CODES.FROYO) { Slog.w(TAG, "Ignoring addPreferredActivity() from uid " + Binder.getCallingUid()); @@ -6788,7 +6855,7 @@ class PackageManagerService extends IPackageManager.Stub { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) != PackageManager.PERMISSION_GRANTED) { - if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid()) + if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid()) < Build.VERSION_CODES.FROYO) { Slog.w(TAG, "Ignoring replacePreferredActivity() from uid " + Binder.getCallingUid()); @@ -6814,14 +6881,15 @@ class PackageManagerService extends IPackageManager.Stub { } public void clearPackagePreferredActivities(String packageName) { + final int uid = Binder.getCallingUid(); + // writer synchronized (mPackages) { - int uid = Binder.getCallingUid(); PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null || pkg.applicationInfo.uid != uid) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) != PackageManager.PERMISSION_GRANTED) { - if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid()) + if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid()) < Build.VERSION_CODES.FROYO) { Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid " + Binder.getCallingUid()); @@ -6832,13 +6900,13 @@ class PackageManagerService extends IPackageManager.Stub { } } - if (clearPackagePreferredActivitiesLP(packageName)) { + if (clearPackagePreferredActivitiesLPw(packageName)) { scheduleWriteSettingsLocked(); } } } - boolean clearPackagePreferredActivitiesLP(String packageName) { + boolean clearPackagePreferredActivitiesLPw(String packageName) { boolean changed = false; Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); while (it.hasNext()) { @@ -6855,10 +6923,11 @@ class PackageManagerService extends IPackageManager.Stub { List<ComponentName> outActivities, String packageName) { int num = 0; + // reader synchronized (mPackages) { - Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); + final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); while (it.hasNext()) { - PreferredActivity pa = it.next(); + final PreferredActivity pa = it.next(); if (packageName == null || pa.mPref.mComponent.getPackageName().equals(packageName)) { if (outFilters != null) { @@ -6903,6 +6972,8 @@ class PackageManagerService extends IPackageManager.Stub { String componentName = isApp ? packageName : className; int packageUid = -1; ArrayList<String> components; + + // writer synchronized (mPackages) { pkgSetting = mSettings.mPackages.get(packageName); if (pkgSetting == null) { @@ -6932,17 +7003,17 @@ class PackageManagerService extends IPackageManager.Stub { // We're dealing with a component level state change switch (newState) { case COMPONENT_ENABLED_STATE_ENABLED: - if (!pkgSetting.enableComponentLP(className)) { + if (!pkgSetting.enableComponentLPw(className)) { return; } break; case COMPONENT_ENABLED_STATE_DISABLED: - if (!pkgSetting.disableComponentLP(className)) { + if (!pkgSetting.disableComponentLPw(className)) { return; } break; case COMPONENT_ENABLED_STATE_DEFAULT: - if (!pkgSetting.restoreComponentLP(className)) { + if (!pkgSetting.restoreComponentLPw(className)) { return; } break; @@ -6951,10 +7022,10 @@ class PackageManagerService extends IPackageManager.Stub { return; } } - mSettings.writeLP(); + mSettings.writeLPr(); packageUid = pkgSetting.userId; components = mPendingBroadcasts.get(packageName); - boolean newPackage = components == null; + final boolean newPackage = components == null; if (newPackage) { components = new ArrayList<String>(); } @@ -6990,8 +7061,9 @@ class PackageManagerService extends IPackageManager.Stub { private void sendPackageChangedBroadcast(String packageName, boolean killFlag, ArrayList<String> componentNames, int packageUid) { - if (false) Log.v(TAG, "Sending package changed: package=" + packageName - + " components=" + componentNames); + if (DEBUG_INSTALL) + Log.v(TAG, "Sending package changed: package=" + packageName + " components=" + + componentNames); Bundle extras = new Bundle(4); extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0)); String nameList[] = new String[componentNames.size()]; @@ -7003,72 +7075,37 @@ class PackageManagerService extends IPackageManager.Stub { } public void setPackageStoppedState(String packageName, boolean stopped) { - PackageSetting pkgSetting; final int uid = Binder.getCallingUid(); final int permission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); + // writer synchronized (mPackages) { - pkgSetting = mSettings.mPackages.get(packageName); - if (pkgSetting == null) { - throw new IllegalArgumentException("Unknown package: " + packageName); - } - if (!allowedByPermission && (uid != pkgSetting.userId)) { - throw new SecurityException( - "Permission Denial: attempt to change stopped state from pid=" - + Binder.getCallingPid() - + ", uid=" + uid + ", package uid=" + pkgSetting.userId); - } - if (DEBUG_STOPPED && stopped) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Slog.i(TAG, "Stopping package " + packageName, e); - } - if (pkgSetting.stopped != stopped) { - pkgSetting.stopped = stopped; - pkgSetting.pkg.mSetStopped = stopped; - if (pkgSetting.notLaunched) { - if (pkgSetting.installerPackageName != null) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, - pkgSetting.name, null, - pkgSetting.installerPackageName, null); - } - pkgSetting.notLaunched = false; - } + if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission, + uid)) { scheduleWriteStoppedPackagesLocked(); } } } public String getInstallerPackageName(String packageName) { + // reader synchronized (mPackages) { - PackageSetting pkg = mSettings.mPackages.get(packageName); - if (pkg == null) { - throw new IllegalArgumentException("Unknown package: " + packageName); - } - return pkg.installerPackageName; + return mSettings.getInstallerPackageNameLPr(packageName); } } - public int getApplicationEnabledSetting(String appPackageName) { + public int getApplicationEnabledSetting(String packageName) { + // reader synchronized (mPackages) { - PackageSetting pkg = mSettings.mPackages.get(appPackageName); - if (pkg == null) { - throw new IllegalArgumentException("Unknown package: " + appPackageName); - } - return pkg.enabled; + return mSettings.getApplicationEnabledSettingLPr(packageName); } } public int getComponentEnabledSetting(ComponentName componentName) { + // reader synchronized (mPackages) { - final String packageNameStr = componentName.getPackageName(); - PackageSetting pkg = mSettings.mPackages.get(packageNameStr); - if (pkg == null) { - throw new IllegalArgumentException("Unknown component: " + componentName); - } - final String classNameStr = componentName.getClassName(); - return pkg.currentEnabledStateLP(classNameStr); + return mSettings.getComponentEnabledSettingLPr(componentName); } } @@ -7112,6 +7149,76 @@ class PackageManagerService extends IPackageManager.Stub { return buf.toString(); } + static class DumpState { + public static final int DUMP_LIBS = 1 << 0; + + public static final int DUMP_FEATURES = 1 << 1; + + public static final int DUMP_RESOLVERS = 1 << 2; + + public static final int DUMP_PERMISSIONS = 1 << 3; + + public static final int DUMP_PACKAGES = 1 << 4; + + public static final int DUMP_SHARED_USERS = 1 << 5; + + public static final int DUMP_MESSAGES = 1 << 6; + + public static final int DUMP_PROVIDERS = 1 << 7; + + public static final int OPTION_SHOW_FILTERS = 1 << 0; + + private int mTypes; + + private int mOptions; + + private boolean mTitlePrinted; + + private SharedUserSetting mSharedUser; + + public boolean isDumping(int type) { + if (mTypes == 0) { + return true; + } + + return (mTypes & type) != 0; + } + + public void setDump(int type) { + mTypes |= type; + } + + public boolean isOptionEnabled(int option) { + return (mOptions & option) != 0; + } + + public void setOptionEnabled(int option) { + mOptions |= option; + } + + public boolean onTitlePrinted() { + final boolean printed = mTitlePrinted; + mTitlePrinted = true; + return printed; + } + + public boolean getTitlePrinted() { + return mTitlePrinted; + } + + public void setTitlePrinted(boolean enabled) { + mTitlePrinted = enabled; + } + + public SharedUserSetting getSharedUser() { + return mSharedUser; + } + + public void setSharedUser(SharedUserSetting user) { + mSharedUser = user; + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -7124,18 +7231,9 @@ class PackageManagerService extends IPackageManager.Stub { return; } - boolean dumpStar = true; - boolean dumpLibs = false; - boolean dumpFeatures = false; - boolean dumpResolvers = false; - boolean dumpPermissions = false; - boolean dumpPackages = false; - boolean dumpSharedUsers = false; - boolean dumpMessages = false; - boolean dumpProviders = false; + DumpState dumpState = new DumpState(); String packageName = null; - boolean showFilters = false; int opti = 0; while (opti < args.length) { @@ -7163,7 +7261,7 @@ class PackageManagerService extends IPackageManager.Stub { pw.println(" <package.name>: info about given package"); return; } else if ("-f".equals(opt)) { - showFilters = true; + dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS); } else { pw.println("Unknown argument: " + opt + "; use -h for help"); } @@ -7177,40 +7275,31 @@ class PackageManagerService extends IPackageManager.Stub { if ("android".equals(cmd) || cmd.contains(".")) { packageName = cmd; } else if ("l".equals(cmd) || "libraries".equals(cmd)) { - dumpStar = false; - dumpLibs = true; + dumpState.setDump(DumpState.DUMP_LIBS); } else if ("f".equals(cmd) || "features".equals(cmd)) { - dumpStar = false; - dumpFeatures = true; + dumpState.setDump(DumpState.DUMP_FEATURES); } else if ("r".equals(cmd) || "resolvers".equals(cmd)) { - dumpStar = false; - dumpResolvers = true; + dumpState.setDump(DumpState.DUMP_RESOLVERS); } else if ("perm".equals(cmd) || "permissions".equals(cmd)) { - dumpStar = false; - dumpPermissions = true; + dumpState.setDump(DumpState.DUMP_PERMISSIONS); } else if ("p".equals(cmd) || "packages".equals(cmd)) { - dumpStar = false; - dumpPackages = true; + dumpState.setDump(DumpState.DUMP_PACKAGES); } else if ("s".equals(cmd) || "shared-users".equals(cmd)) { - dumpStar = false; - dumpSharedUsers = true; + dumpState.setDump(DumpState.DUMP_SHARED_USERS); } else if ("prov".equals(cmd) || "providers".equals(cmd)) { - dumpStar = false; - dumpProviders = true; + dumpState.setDump(DumpState.DUMP_PROVIDERS); } else if ("m".equals(cmd) || "messages".equals(cmd)) { - dumpStar = false; - dumpMessages = true; + dumpState.setDump(DumpState.DUMP_MESSAGES); } } - - boolean printedTitle = false; - + + // reader synchronized (mPackages) { - if ((dumpStar || dumpLibs) && packageName == null) { - if (printedTitle) pw.println(" "); - printedTitle = true; + if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) { + if (dumpState.onTitlePrinted()) + pw.println(" "); pw.println("Libraries:"); - Iterator<String> it = mSharedLibraries.keySet().iterator(); + final Iterator<String> it = mSharedLibraries.keySet().iterator(); while (it.hasNext()) { String name = it.next(); pw.print(" "); @@ -7220,9 +7309,9 @@ class PackageManagerService extends IPackageManager.Stub { } } - if ((dumpStar || dumpFeatures) && packageName == null) { - if (printedTitle) pw.println(" "); - printedTitle = true; + if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) { + if (dumpState.onTitlePrinted()) + pw.println(" "); pw.println("Features:"); Iterator<String> it = mAvailableFeatures.keySet().iterator(); while (it.hasNext()) { @@ -7232,276 +7321,72 @@ class PackageManagerService extends IPackageManager.Stub { } } - if (dumpStar || dumpResolvers) { - if (mActivities.dump(pw, printedTitle - ? "\nActivity Resolver Table:" : "Activity Resolver Table:", - " ", packageName, showFilters)) { - printedTitle = true; + if (dumpState.isDumping(DumpState.DUMP_RESOLVERS)) { + if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:" + : "Activity Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) { + dumpState.setTitlePrinted(true); } - if (mReceivers.dump(pw, printedTitle - ? "\nReceiver Resolver Table:" : "Receiver Resolver Table:", - " ", packageName, showFilters)) { - printedTitle = true; + if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:" + : "Receiver Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) { + dumpState.setTitlePrinted(true); } - if (mServices.dump(pw, printedTitle - ? "\nService Resolver Table:" : "Service Resolver Table:", - " ", packageName, showFilters)) { - printedTitle = true; + if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:" + : "Service Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) { + dumpState.setTitlePrinted(true); } - if (mSettings.mPreferredActivities.dump(pw, printedTitle - ? "\nPreferred Activities:" : "Preferred Activities:", - " ", packageName, showFilters)) { - printedTitle = true; + if (mSettings.mPreferredActivities.dump(pw, + dumpState.getTitlePrinted() ? "\nPreferred Activities:" + : "Preferred Activities:", " ", + packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) { + dumpState.setTitlePrinted(true); } } - boolean printedSomething = false; - if (dumpStar || dumpPermissions) { - for (BasePermission p : mSettings.mPermissions.values()) { - if (packageName != null && !packageName.equals(p.sourcePackage)) { - continue; - } - if (!printedSomething) { - if (printedTitle) pw.println(" "); - pw.println("Permissions:"); - printedSomething = true; - printedTitle = true; - } - pw.print(" Permission ["); pw.print(p.name); pw.print("] ("); - pw.print(Integer.toHexString(System.identityHashCode(p))); - pw.println("):"); - pw.print(" sourcePackage="); pw.println(p.sourcePackage); - pw.print(" uid="); pw.print(p.uid); - pw.print(" gids="); pw.print(arrayToString(p.gids)); - pw.print(" type="); pw.print(p.type); - pw.print(" prot="); pw.println(p.protectionLevel); - if (p.packageSetting != null) { - pw.print(" packageSetting="); pw.println(p.packageSetting); - } - if (p.perm != null) { - pw.print(" perm="); pw.println(p.perm); - } - } + if (dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) { + mSettings.dumpPermissionsLPr(pw, packageName, dumpState); } - if (dumpStar || dumpProviders) { - printedSomething = false; + if (dumpState.isDumping(DumpState.DUMP_PROVIDERS)) { + boolean printedSomething = false; for (PackageParser.Provider p : mProviders.values()) { if (packageName != null && !packageName.equals(p.info.packageName)) { continue; } if (!printedSomething) { - if (printedTitle) pw.println(" "); + if (dumpState.onTitlePrinted()) + pw.println(" "); pw.println("Registered ContentProviders:"); printedSomething = true; - printedTitle = true; } pw.print(" ["); pw.print(p.info.authority); pw.print("]: "); pw.println(p.toString()); } } - printedSomething = false; - SharedUserSetting packageSharedUser = null; - if (dumpStar || dumpPackages) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Date date = new Date(); - for (PackageSetting ps : mSettings.mPackages.values()) { - if (packageName != null && !packageName.equals(ps.realName) - && !packageName.equals(ps.name)) { - continue; - } - if (!printedSomething) { - if (printedTitle) pw.println(" "); - pw.println("Packages:"); - printedSomething = true; - printedTitle = true; - } - packageSharedUser = ps.sharedUser; - pw.print(" Package ["); - pw.print(ps.realName != null ? ps.realName : ps.name); - pw.print("] ("); - pw.print(Integer.toHexString(System.identityHashCode(ps))); - pw.println("):"); - if (ps.realName != null) { - pw.print(" compat name="); pw.println(ps.name); - } - pw.print(" userId="); pw.print(ps.userId); - pw.print(" gids="); pw.println(arrayToString(ps.gids)); - pw.print(" sharedUser="); pw.println(ps.sharedUser); - pw.print(" pkg="); pw.println(ps.pkg); - pw.print(" codePath="); pw.println(ps.codePathString); - pw.print(" resourcePath="); pw.println(ps.resourcePathString); - pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); - pw.print(" versionCode="); pw.println(ps.versionCode); - if (ps.pkg != null) { - pw.print(" versionName="); pw.println(ps.pkg.mVersionName); - pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); - pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion); - if (ps.pkg.mOperationPending) { - pw.println(" mOperationPending=true"); - } - pw.print(" supportsScreens=["); - boolean first = true; - if ((ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { - if (!first) pw.print(", "); - first = false; - pw.print("small"); - } - if ((ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { - if (!first) pw.print(", "); - first = false; - pw.print("medium"); - } - if ((ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - if (!first) pw.print(", "); - first = false; - pw.print("large"); - } - if ((ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { - if (!first) pw.print(", "); - first = false; - pw.print("xlarge"); - } - if ((ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { - if (!first) pw.print(", "); - first = false; - pw.print("resizeable"); - } - if ((ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { - if (!first) pw.print(", "); - first = false; - pw.print("anyDensity"); - } - } - pw.println("]"); - pw.print(" timeStamp="); - date.setTime(ps.timeStamp); pw.println(sdf.format(date)); - pw.print(" firstInstallTime="); - date.setTime(ps.firstInstallTime); pw.println(sdf.format(date)); - pw.print(" lastUpdateTime="); - date.setTime(ps.lastUpdateTime); pw.println(sdf.format(date)); - if (ps.installerPackageName != null) { - pw.print(" installerPackageName="); pw.println(ps.installerPackageName); - } - pw.print(" signatures="); pw.println(ps.signatures); - pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed); - pw.print(" haveGids="); pw.println(ps.haveGids); - pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); - pw.print(" installStatus="); pw.print(ps.installStatus); - pw.print(" stopped="); pw.print(ps.stopped); - pw.print(" enabled="); pw.println(ps.enabled); - if (ps.disabledComponents.size() > 0) { - pw.println(" disabledComponents:"); - for (String s : ps.disabledComponents) { - pw.print(" "); pw.println(s); - } - } - if (ps.enabledComponents.size() > 0) { - pw.println(" enabledComponents:"); - for (String s : ps.enabledComponents) { - pw.print(" "); pw.println(s); - } - } - if (ps.grantedPermissions.size() > 0) { - pw.println(" grantedPermissions:"); - for (String s : ps.grantedPermissions) { - pw.print(" "); pw.println(s); - } - } - } + if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) { + mSettings.dumpPackagesLPr(pw, packageName, dumpState); } - printedSomething = false; - if (dumpStar || dumpPackages) { - if (mSettings.mRenamedPackages.size() > 0) { - for (HashMap.Entry<String, String> e - : mSettings.mRenamedPackages.entrySet()) { - if (packageName != null && !packageName.equals(e.getKey()) - && !packageName.equals(e.getValue())) { - continue; - } - if (!printedSomething) { - if (printedTitle) pw.println(" "); - pw.println("Renamed packages:"); - printedSomething = true; - printedTitle = true; - } - pw.print(" "); pw.print(e.getKey()); pw.print(" -> "); - pw.println(e.getValue()); - } - } - printedSomething = false; - if (mSettings.mDisabledSysPackages.size() > 0) { - for (PackageSetting ps : mSettings.mDisabledSysPackages.values()) { - if (packageName != null && !packageName.equals(ps.realName) - && !packageName.equals(ps.name)) { - continue; - } - if (!printedSomething) { - if (printedTitle) pw.println(" "); - pw.println("Hidden system packages:"); - printedSomething = true; - printedTitle = true; - } - pw.print(" Package ["); - pw.print(ps.realName != null ? ps.realName : ps.name); - pw.print("] ("); - pw.print(Integer.toHexString(System.identityHashCode(ps))); - pw.println("):"); - if (ps.realName != null) { - pw.print(" compat name="); pw.println(ps.name); - } - pw.print(" userId="); pw.println(ps.userId); - pw.print(" sharedUser="); pw.println(ps.sharedUser); - pw.print(" codePath="); pw.println(ps.codePathString); - pw.print(" resourcePath="); pw.println(ps.resourcePathString); - } - } - } - printedSomething = false; - if (dumpStar || dumpSharedUsers) { - for (SharedUserSetting su : mSettings.mSharedUsers.values()) { - if (packageName != null && su != packageSharedUser) { - continue; - } - if (!printedSomething) { - if (printedTitle) pw.println(" "); - pw.println("Shared users:"); - printedSomething = true; - printedTitle = true; - } - pw.print(" SharedUser ["); pw.print(su.name); pw.print("] ("); - pw.print(Integer.toHexString(System.identityHashCode(su))); - pw.println("):"); - pw.print(" userId="); pw.print(su.userId); - pw.print(" gids="); pw.println(arrayToString(su.gids)); - pw.println(" grantedPermissions:"); - for (String s : su.grantedPermissions) { - pw.print(" "); pw.println(s); - } - } + + if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) { + mSettings.dumpSharedUsersLPr(pw, packageName, dumpState); } - - if ((dumpStar || dumpMessages) && packageName == null) { - if (printedTitle) pw.println(" "); - printedTitle = true; - pw.println("Settings parse messages:"); - pw.print(mSettings.mReadMessages.toString()); - + + if (dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) { + if (dumpState.onTitlePrinted()) + pw.println(" "); + mSettings.dumpReadMessagesLPr(pw, dumpState); + pw.println(" "); pw.println("Package warning messages:"); - File fname = getSettingsProblemFile(); + final File fname = getSettingsProblemFile(); FileInputStream in = null; try { in = new FileInputStream(fname); - int avail = in.available(); - byte[] data = new byte[avail]; + final int avail = in.available(); + final byte[] data = new byte[avail]; in.read(data); pw.print(new String(data)); } catch (FileNotFoundException e) { @@ -7510,7 +7395,7 @@ class PackageManagerService extends IPackageManager.Stub { if (in != null) { try { in.close(); - } catch (IOException e) { + } catch (IOException e) { } } } @@ -7518,2904 +7403,505 @@ class PackageManagerService extends IPackageManager.Stub { } } - static final class BasePermission { - final static int TYPE_NORMAL = 0; - final static int TYPE_BUILTIN = 1; - final static int TYPE_DYNAMIC = 2; - - final String name; - String sourcePackage; - PackageSettingBase packageSetting; - final int type; - int protectionLevel; - PackageParser.Permission perm; - PermissionInfo pendingInfo; - int uid; - int[] gids; - - BasePermission(String _name, String _sourcePackage, int _type) { - name = _name; - sourcePackage = _sourcePackage; - type = _type; - // Default to most conservative protection level. - protectionLevel = PermissionInfo.PROTECTION_SIGNATURE; - } - - public String toString() { - return "BasePermission{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + name + "}"; - } - } - - static class PackageSignatures { - private Signature[] mSignatures; - - PackageSignatures(PackageSignatures orig) { - if (orig != null && orig.mSignatures != null) { - mSignatures = orig.mSignatures.clone(); - } - } - - PackageSignatures(Signature[] sigs) { - assignSignatures(sigs); - } - - PackageSignatures() { - } - - void writeXml(XmlSerializer serializer, String tagName, - ArrayList<Signature> pastSignatures) throws IOException { - if (mSignatures == null) { - return; - } - serializer.startTag(null, tagName); - serializer.attribute(null, "count", - Integer.toString(mSignatures.length)); - for (int i=0; i<mSignatures.length; i++) { - serializer.startTag(null, "cert"); - final Signature sig = mSignatures[i]; - final int sigHash = sig.hashCode(); - final int numPast = pastSignatures.size(); - int j; - for (j=0; j<numPast; j++) { - Signature pastSig = pastSignatures.get(j); - if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) { - serializer.attribute(null, "index", Integer.toString(j)); - break; - } - } - if (j >= numPast) { - pastSignatures.add(sig); - serializer.attribute(null, "index", Integer.toString(numPast)); - serializer.attribute(null, "key", sig.toCharsString()); - } - serializer.endTag(null, "cert"); - } - serializer.endTag(null, tagName); - } - - void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures) - throws IOException, XmlPullParserException { - String countStr = parser.getAttributeValue(null, "count"); - if (countStr == null) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <signatures> has" - + " no count at " + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - } - final int count = Integer.parseInt(countStr); - mSignatures = new Signature[count]; - int pos = 0; - - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("cert")) { - if (pos < count) { - String index = parser.getAttributeValue(null, "index"); - if (index != null) { - try { - int idx = Integer.parseInt(index); - String key = parser.getAttributeValue(null, "key"); - if (key == null) { - if (idx >= 0 && idx < pastSignatures.size()) { - Signature sig = pastSignatures.get(idx); - if (sig != null) { - mSignatures[pos] = pastSignatures.get(idx); - pos++; - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <cert> " - + "index " + index + " is not defined at " - + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <cert> " - + "index " + index + " is out of bounds at " - + parser.getPositionDescription()); - } - } else { - while (pastSignatures.size() <= idx) { - pastSignatures.add(null); - } - Signature sig = new Signature(key); - pastSignatures.set(idx, sig); - mSignatures[pos] = sig; - pos++; - } - } catch (NumberFormatException e) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <cert> " - + "index " + index + " is not a number at " - + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <cert> has" - + " no index at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: too " - + "many <cert> tags, expected " + count - + " at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <cert>: " - + parser.getName()); - } - XmlUtils.skipCurrentTag(parser); - } - - if (pos < count) { - // Should never happen -- there is an error in the written - // settings -- but if it does we don't want to generate - // a bad array. - Signature[] newSigs = new Signature[pos]; - System.arraycopy(mSignatures, 0, newSigs, 0, pos); - mSignatures = newSigs; - } - } - - private void assignSignatures(Signature[] sigs) { - if (sigs == null) { - mSignatures = null; - return; - } - mSignatures = new Signature[sigs.length]; - for (int i=0; i<sigs.length; i++) { - mSignatures[i] = sigs[i]; - } - } - - @Override - public String toString() { - StringBuffer buf = new StringBuffer(128); - buf.append("PackageSignatures{"); - buf.append(Integer.toHexString(System.identityHashCode(this))); - buf.append(" ["); - if (mSignatures != null) { - for (int i=0; i<mSignatures.length; i++) { - if (i > 0) buf.append(", "); - buf.append(Integer.toHexString( - System.identityHashCode(mSignatures[i]))); - } - } - buf.append("]}"); - return buf.toString(); - } - } - - static class PreferredActivity extends IntentFilter implements PreferredComponent.Callbacks { - final PreferredComponent mPref; - - PreferredActivity(IntentFilter filter, int match, ComponentName[] set, - ComponentName activity) { - super(filter); - mPref = new PreferredComponent(this, match, set, activity); - } - - PreferredActivity(XmlPullParser parser) throws XmlPullParserException, - IOException { - mPref = new PreferredComponent(this, parser); - } - - public void writeToXml(XmlSerializer serializer) throws IOException { - mPref.writeToXml(serializer); - serializer.startTag(null, "filter"); - super.writeToXml(serializer); - serializer.endTag(null, "filter"); - } - - public boolean onReadTag(String tagName, XmlPullParser parser) - throws XmlPullParserException, IOException { - if (tagName.equals("filter")) { - //Log.i(TAG, "Starting to parse filter..."); - readFromXml(parser); - //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth=" - // + parser.getDepth() + " tag=" + parser.getName()); - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <preferred-activities>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - return true; - } - } - - static class GrantedPermissions { - int pkgFlags; - - HashSet<String> grantedPermissions = new HashSet<String>(); - int[] gids; - - GrantedPermissions(int pkgFlags) { - setFlags(pkgFlags); - } - - GrantedPermissions(GrantedPermissions base) { - pkgFlags = base.pkgFlags; - grantedPermissions = (HashSet<String>) base.grantedPermissions.clone(); - - if (base.gids != null) { - gids = base.gids.clone(); - } - } - - void setFlags(int pkgFlags) { - this.pkgFlags = pkgFlags & ( - ApplicationInfo.FLAG_SYSTEM | - ApplicationInfo.FLAG_FORWARD_LOCK | - ApplicationInfo.FLAG_EXTERNAL_STORAGE); - } - } - - /** - * Settings base class for pending and resolved classes. - */ - static class PackageSettingBase extends GrantedPermissions { - final String name; - final String realName; - File codePath; - String codePathString; - File resourcePath; - String resourcePathString; - String nativeLibraryPathString; - long timeStamp; - long firstInstallTime; - long lastUpdateTime; - int versionCode; - - boolean uidError; - - PackageSignatures signatures = new PackageSignatures(); - - boolean permissionsFixed; - boolean haveGids; - - // Whether this package is currently stopped, thus can not be - // started until explicitly launched by the user. - public boolean stopped; - - // Set to true if we have never launched this app. - public boolean notLaunched; - - /* Explicitly disabled components */ - HashSet<String> disabledComponents = new HashSet<String>(0); - /* Explicitly enabled components */ - HashSet<String> enabledComponents = new HashSet<String>(0); - int enabled = COMPONENT_ENABLED_STATE_DEFAULT; - int installStatus = PKG_INSTALL_COMPLETE; - - PackageSettingBase origPackage; - - /* package name of the app that installed this package */ - String installerPackageName; - - PackageSettingBase(String name, String realName, File codePath, File resourcePath, - String nativeLibraryPathString, int pVersionCode, int pkgFlags) { - super(pkgFlags); - this.name = name; - this.realName = realName; - init(codePath, resourcePath, nativeLibraryPathString, pVersionCode); - } - - /** - * New instance of PackageSetting with one-level-deep cloning. - */ - PackageSettingBase(PackageSettingBase base) { - super(base); - - name = base.name; - realName = base.realName; - codePath = base.codePath; - codePathString = base.codePathString; - resourcePath = base.resourcePath; - resourcePathString = base.resourcePathString; - nativeLibraryPathString = base.nativeLibraryPathString; - timeStamp = base.timeStamp; - firstInstallTime = base.firstInstallTime; - lastUpdateTime = base.lastUpdateTime; - versionCode = base.versionCode; - - uidError = base.uidError; - - signatures = new PackageSignatures(base.signatures); - - permissionsFixed = base.permissionsFixed; - haveGids = base.haveGids; - stopped = base.stopped; - notLaunched = base.notLaunched; - - disabledComponents = (HashSet<String>) base.disabledComponents.clone(); - - enabledComponents = (HashSet<String>) base.enabledComponents.clone(); - - enabled = base.enabled; - installStatus = base.installStatus; - - origPackage = base.origPackage; - - installerPackageName = base.installerPackageName; - } - - void init(File codePath, File resourcePath, String nativeLibraryPathString, - int pVersionCode) { - this.codePath = codePath; - this.codePathString = codePath.toString(); - this.resourcePath = resourcePath; - this.resourcePathString = resourcePath.toString(); - this.nativeLibraryPathString = nativeLibraryPathString; - this.versionCode = pVersionCode; - } - - public void setInstallerPackageName(String packageName) { - installerPackageName = packageName; - } - - String getInstallerPackageName() { - return installerPackageName; - } - - public void setInstallStatus(int newStatus) { - installStatus = newStatus; - } - - public int getInstallStatus() { - return installStatus; - } - - public void setTimeStamp(long newStamp) { - timeStamp = newStamp; - } - - /** - * Make a shallow copy of this package settings. - */ - public void copyFrom(PackageSettingBase base) { - grantedPermissions = base.grantedPermissions; - gids = base.gids; - - timeStamp = base.timeStamp; - firstInstallTime = base.firstInstallTime; - lastUpdateTime = base.lastUpdateTime; - signatures = base.signatures; - permissionsFixed = base.permissionsFixed; - haveGids = base.haveGids; - stopped = base.stopped; - notLaunched = base.notLaunched; - disabledComponents = base.disabledComponents; - enabledComponents = base.enabledComponents; - enabled = base.enabled; - installStatus = base.installStatus; - } - - boolean enableComponentLP(String componentClassName) { - boolean changed = disabledComponents.remove(componentClassName); - changed |= enabledComponents.add(componentClassName); - return changed; - } - - boolean disableComponentLP(String componentClassName) { - boolean changed = enabledComponents.remove(componentClassName); - changed |= disabledComponents.add(componentClassName); - return changed; - } - - boolean restoreComponentLP(String componentClassName) { - boolean changed = enabledComponents.remove(componentClassName); - changed |= disabledComponents.remove(componentClassName); - return changed; - } - - int currentEnabledStateLP(String componentName) { - if (enabledComponents.contains(componentName)) { - return COMPONENT_ENABLED_STATE_ENABLED; - } else if (disabledComponents.contains(componentName)) { - return COMPONENT_ENABLED_STATE_DISABLED; - } else { - return COMPONENT_ENABLED_STATE_DEFAULT; - } - } - } - - /** - * Settings data for a particular package we know about. - */ - static final class PackageSetting extends PackageSettingBase { - int userId; - PackageParser.Package pkg; - SharedUserSetting sharedUser; - - PackageSetting(String name, String realName, File codePath, File resourcePath, - String nativeLibraryPathString, int pVersionCode, int pkgFlags) { - super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode, - pkgFlags); - } - - /** - * New instance of PackageSetting replicating the original settings. - * Note that it keeps the same PackageParser.Package instance. - */ - PackageSetting(PackageSetting orig) { - super(orig); - - userId = orig.userId; - pkg = orig.pkg; - sharedUser = orig.sharedUser; - } - - @Override - public String toString() { - return "PackageSetting{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + name + "/" + userId + "}"; - } - } - - /** - * Settings data for a particular shared user ID we know about. - */ - static final class SharedUserSetting extends GrantedPermissions { - final String name; - int userId; - final HashSet<PackageSetting> packages = new HashSet<PackageSetting>(); - final PackageSignatures signatures = new PackageSignatures(); - - SharedUserSetting(String _name, int _pkgFlags) { - super(_pkgFlags); - name = _name; - } - - @Override - public String toString() { - return "SharedUserSetting{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + name + "/" + userId + "}"; - } - } - - /** - * Holds information about dynamic settings. - */ - private static final class Settings { - private final File mSettingsFilename; - private final File mBackupSettingsFilename; - private final File mPackageListFilename; - private final File mStoppedPackagesFilename; - private final File mBackupStoppedPackagesFilename; - private final HashMap<String, PackageSetting> mPackages = - new HashMap<String, PackageSetting>(); - // List of replaced system applications - final HashMap<String, PackageSetting> mDisabledSysPackages = - new HashMap<String, PackageSetting>(); - - // These are the last platform API version we were using for - // the apps installed on internal and external storage. It is - // used to grant newer permissions one time during a system upgrade. - int mInternalSdkPlatform; - int mExternalSdkPlatform; - - // The user's preferred activities associated with particular intent - // filters. - private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities = - new IntentResolver<PreferredActivity, PreferredActivity>() { - @Override - protected String packageForFilter(PreferredActivity filter) { - return filter.mPref.mComponent.getPackageName(); - } - @Override - protected void dumpFilter(PrintWriter out, String prefix, - PreferredActivity filter) { - filter.mPref.dump(out, prefix, filter); - } - }; - private final HashMap<String, SharedUserSetting> mSharedUsers = - new HashMap<String, SharedUserSetting>(); - private final ArrayList<Object> mUserIds = new ArrayList<Object>(); - private final SparseArray<Object> mOtherUserIds = - new SparseArray<Object>(); - - // For reading/writing settings file. - private final ArrayList<Signature> mPastSignatures = - new ArrayList<Signature>(); - - // Mapping from permission names to info about them. - final HashMap<String, BasePermission> mPermissions = - new HashMap<String, BasePermission>(); - - // Mapping from permission tree names to info about them. - final HashMap<String, BasePermission> mPermissionTrees = - new HashMap<String, BasePermission>(); - - // Packages that have been uninstalled and still need their external - // storage data deleted. - final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>(); - - // Packages that have been renamed since they were first installed. - // Keys are the new names of the packages, values are the original - // names. The packages appear everwhere else under their original - // names. - final HashMap<String, String> mRenamedPackages = new HashMap<String, String>(); - - private final StringBuilder mReadMessages = new StringBuilder(); - - private static final class PendingPackage extends PackageSettingBase { - final int sharedId; - - PendingPackage(String name, String realName, File codePath, File resourcePath, - String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) { - super(name, realName, codePath, resourcePath, nativeLibraryPathString, - pVersionCode, pkgFlags); - this.sharedId = sharedId; - } - } - private final ArrayList<PendingPackage> mPendingPackages - = new ArrayList<PendingPackage>(); - - Settings() { - File dataDir = Environment.getDataDirectory(); - File systemDir = new File(dataDir, "system"); - // TODO(oam): This secure dir creation needs to be moved somewhere else (later) - File systemSecureDir = new File(dataDir, "secure/system"); - systemDir.mkdirs(); - systemSecureDir.mkdirs(); - FileUtils.setPermissions(systemDir.toString(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG - |FileUtils.S_IROTH|FileUtils.S_IXOTH, - -1, -1); - FileUtils.setPermissions(systemSecureDir.toString(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG - |FileUtils.S_IROTH|FileUtils.S_IXOTH, - -1, -1); - mSettingsFilename = new File(systemDir, "packages.xml"); - mBackupSettingsFilename = new File(systemDir, "packages-backup.xml"); - mPackageListFilename = new File(systemDir, "packages.list"); - mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml"); - mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml"); - } - - PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage, - String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, - String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) { - final String name = pkg.packageName; - PackageSetting p = getPackageLP(name, origPackage, realName, sharedUser, codePath, - resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add); - return p; - } - - PackageSetting peekPackageLP(String name) { - return mPackages.get(name); - /* - PackageSetting p = mPackages.get(name); - if (p != null && p.codePath.getPath().equals(codePath)) { - return p; - } - return null; - */ - } - - void setInstallStatus(String pkgName, int status) { - PackageSetting p = mPackages.get(pkgName); - if(p != null) { - if(p.getInstallStatus() != status) { - p.setInstallStatus(status); - } - } - } + // ------- apps on sdcard specific code ------- + static final boolean DEBUG_SD_INSTALL = false; - void setInstallerPackageName(String pkgName, - String installerPkgName) { - PackageSetting p = mPackages.get(pkgName); - if(p != null) { - p.setInstallerPackageName(installerPkgName); - } - } + private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD"; - String getInstallerPackageName(String pkgName) { - PackageSetting p = mPackages.get(pkgName); - return (p == null) ? null : p.getInstallerPackageName(); - } + private static final String SD_ENCRYPTION_ALGORITHM = "AES"; - int getInstallStatus(String pkgName) { - PackageSetting p = mPackages.get(pkgName); - if(p != null) { - return p.getInstallStatus(); - } - return -1; - } + private boolean mMediaMounted = false; - SharedUserSetting getSharedUserLP(String name, - int pkgFlags, boolean create) { - SharedUserSetting s = mSharedUsers.get(name); - if (s == null) { - if (!create) { + private String getEncryptKey() { + try { + String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString( + SD_ENCRYPTION_KEYSTORE_NAME); + if (sdEncKey == null) { + sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128, + SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME); + if (sdEncKey == null) { + Slog.e(TAG, "Failed to create encryption keys"); return null; } - s = new SharedUserSetting(name, pkgFlags); - if (MULTIPLE_APPLICATION_UIDS) { - s.userId = newUserIdLP(s); - } else { - s.userId = FIRST_APPLICATION_UID; - } - Log.i(TAG, "New shared user " + name + ": id=" + s.userId); - // < 0 means we couldn't assign a userid; fall out and return - // s, which is currently null - if (s.userId >= 0) { - mSharedUsers.put(name, s); - } - } - - return s; - } - - boolean disableSystemPackageLP(String name) { - PackageSetting p = mPackages.get(name); - if(p == null) { - Log.w(TAG, "Package:"+name+" is not an installed package"); - return false; - } - PackageSetting dp = mDisabledSysPackages.get(name); - // always make sure the system package code and resource paths dont change - if (dp == null) { - if((p.pkg != null) && (p.pkg.applicationInfo != null)) { - p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - } - mDisabledSysPackages.put(name, p); - - // a little trick... when we install the new package, we don't - // want to modify the existing PackageSetting for the built-in - // version. so at this point we need a new PackageSetting that - // is okay to muck with. - PackageSetting newp = new PackageSetting(p); - replacePackageLP(name, newp); - return true; - } - return false; - } - - PackageSetting enableSystemPackageLP(String name) { - PackageSetting p = mDisabledSysPackages.get(name); - if(p == null) { - Log.w(TAG, "Package:"+name+" is not disabled"); - return null; - } - // Reset flag in ApplicationInfo object - if((p.pkg != null) && (p.pkg.applicationInfo != null)) { - p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - } - PackageSetting ret = addPackageLP(name, p.realName, p.codePath, p.resourcePath, - p.nativeLibraryPathString, p.userId, p.versionCode, p.pkgFlags); - mDisabledSysPackages.remove(name); - return ret; - } - - PackageSetting addPackageLP(String name, String realName, File codePath, File resourcePath, - String nativeLibraryPathString, int uid, int vc, int pkgFlags) { - PackageSetting p = mPackages.get(name); - if (p != null) { - if (p.userId == uid) { - return p; - } - reportSettingsProblem(Log.ERROR, - "Adding duplicate package, keeping first: " + name); - return null; - } - p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, - vc, pkgFlags); - p.userId = uid; - if (addUserIdLP(uid, p, name)) { - mPackages.put(name, p); - return p; } + return sdEncKey; + } catch (NoSuchAlgorithmException nsae) { + Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae); return null; - } - - SharedUserSetting addSharedUserLP(String name, int uid, int pkgFlags) { - SharedUserSetting s = mSharedUsers.get(name); - if (s != null) { - if (s.userId == uid) { - return s; - } - reportSettingsProblem(Log.ERROR, - "Adding duplicate shared user, keeping first: " + name); - return null; - } - s = new SharedUserSetting(name, pkgFlags); - s.userId = uid; - if (addUserIdLP(uid, s, name)) { - mSharedUsers.put(name, s); - return s; - } + } catch (IOException ioe) { + Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe); return null; } - // Transfer ownership of permissions from one package to another. - private void transferPermissions(String origPkg, String newPkg) { - // Transfer ownership of permissions to the new package. - for (int i=0; i<2; i++) { - HashMap<String, BasePermission> permissions = - i == 0 ? mPermissionTrees : mPermissions; - for (BasePermission bp : permissions.values()) { - if (origPkg.equals(bp.sourcePackage)) { - if (DEBUG_UPGRADE) Log.v(TAG, - "Moving permission " + bp.name - + " from pkg " + bp.sourcePackage - + " to " + newPkg); - bp.sourcePackage = newPkg; - bp.packageSetting = null; - bp.perm = null; - if (bp.pendingInfo != null) { - bp.pendingInfo.packageName = newPkg; - } - bp.uid = 0; - bp.gids = null; - } - } - } - } - - private PackageSetting getPackageLP(String name, PackageSetting origPackage, - String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, - String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) { - PackageSetting p = mPackages.get(name); - if (p != null) { - if (!p.codePath.equals(codePath)) { - // Check to see if its a disabled system app - if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { - // This is an updated system app with versions in both system - // and data partition. Just let the most recent version - // take precedence. - Slog.w(TAG, "Trying to update system app code path from " + - p.codePathString + " to " + codePath.toString()); - } else { - // Just a change in the code path is not an issue, but - // let's log a message about it. - Slog.i(TAG, "Package " + name + " codePath changed from " + p.codePath - + " to " + codePath + "; Retaining data and using new"); - /* - * Since we've changed paths, we need to prefer the new - * native library path over the one stored in the - * package settings since we might have moved from - * internal to external storage or vice versa. - */ - p.nativeLibraryPathString = nativeLibraryPathString; - } - } - if (p.sharedUser != sharedUser) { - reportSettingsProblem(Log.WARN, - "Package " + name + " shared user changed from " - + (p.sharedUser != null ? p.sharedUser.name : "<nothing>") - + " to " - + (sharedUser != null ? sharedUser.name : "<nothing>") - + "; replacing with new"); - p = null; - } else { - if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) { - // If what we are scanning is a system package, then - // make it so, regardless of whether it was previously - // installed only in the data partition. - p.pkgFlags |= ApplicationInfo.FLAG_SYSTEM; - } - } - } - if (p == null) { - // Create a new PackageSettings entry. this can end up here because - // of code path mismatch or user id mismatch of an updated system partition - if (!create) { - return null; - } - if (origPackage != null) { - // We are consuming the data from an existing package. - p = new PackageSetting(origPackage.name, name, codePath, resourcePath, - nativeLibraryPathString, vc, pkgFlags); - if (DEBUG_UPGRADE) Log.v(TAG, "Package " + name - + " is adopting original package " + origPackage.name); - // Note that we will retain the new package's signature so - // that we can keep its data. - PackageSignatures s = p.signatures; - p.copyFrom(origPackage); - p.signatures = s; - p.sharedUser = origPackage.sharedUser; - p.userId = origPackage.userId; - p.origPackage = origPackage; - mRenamedPackages.put(name, origPackage.name); - name = origPackage.name; - // Update new package state. - p.setTimeStamp(codePath.lastModified()); - } else { - p = new PackageSetting(name, realName, codePath, resourcePath, - nativeLibraryPathString, vc, pkgFlags); - p.setTimeStamp(codePath.lastModified()); - p.sharedUser = sharedUser; - // If this is not a system app, it starts out stopped. - if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { - if (DEBUG_STOPPED) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Slog.i(TAG, "Stopping package " + name, e); - } - p.stopped = true; - p.notLaunched = true; - } - if (sharedUser != null) { - p.userId = sharedUser.userId; - } else if (MULTIPLE_APPLICATION_UIDS) { - // Clone the setting here for disabled system packages - PackageSetting dis = mDisabledSysPackages.get(name); - if (dis != null) { - // For disabled packages a new setting is created - // from the existing user id. This still has to be - // added to list of user id's - // Copy signatures from previous setting - if (dis.signatures.mSignatures != null) { - p.signatures.mSignatures = dis.signatures.mSignatures.clone(); - } - p.userId = dis.userId; - // Clone permissions - p.grantedPermissions = new HashSet<String>(dis.grantedPermissions); - // Clone component info - p.disabledComponents = new HashSet<String>(dis.disabledComponents); - p.enabledComponents = new HashSet<String>(dis.enabledComponents); - // Add new setting to list of user ids - addUserIdLP(p.userId, p, name); - } else { - // Assign new user id - p.userId = newUserIdLP(p); - } - } else { - p.userId = FIRST_APPLICATION_UID; - } - } - if (p.userId < 0) { - reportSettingsProblem(Log.WARN, - "Package " + name + " could not be assigned a valid uid"); - return null; - } - if (add) { - // Finish adding new package by adding it and updating shared - // user preferences - addPackageSettingLP(p, name, sharedUser); - } - } - return p; - } - - private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) { - p.pkg = pkg; - pkg.mSetEnabled = p.enabled; - pkg.mSetStopped = p.stopped; - final String codePath = pkg.applicationInfo.sourceDir; - final String resourcePath = pkg.applicationInfo.publicSourceDir; - // Update code path if needed - if (!codePath.equalsIgnoreCase(p.codePathString)) { - Slog.w(TAG, "Code path for pkg : " + p.pkg.packageName + - " changing from " + p.codePathString + " to " + codePath); - p.codePath = new File(codePath); - p.codePathString = codePath; - } - //Update resource path if needed - if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) { - Slog.w(TAG, "Resource path for pkg : " + p.pkg.packageName + - " changing from " + p.resourcePathString + " to " + resourcePath); - p.resourcePath = new File(resourcePath); - p.resourcePathString = resourcePath; - } - // Update the native library path if needed - final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir; - if (nativeLibraryPath != null - && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) { - p.nativeLibraryPathString = nativeLibraryPath; - } - // Update version code if needed - if (pkg.mVersionCode != p.versionCode) { - p.versionCode = pkg.mVersionCode; - } - // Update signatures if needed. - if (p.signatures.mSignatures == null) { - p.signatures.assignSignatures(pkg.mSignatures); - } - // If this app defines a shared user id initialize - // the shared user signatures as well. - if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) { - p.sharedUser.signatures.assignSignatures(pkg.mSignatures); - } - addPackageSettingLP(p, pkg.packageName, p.sharedUser); - } - - // Utility method that adds a PackageSetting to mPackages and - // completes updating the shared user attributes - private void addPackageSettingLP(PackageSetting p, String name, - SharedUserSetting sharedUser) { - mPackages.put(name, p); - if (sharedUser != null) { - if (p.sharedUser != null && p.sharedUser != sharedUser) { - reportSettingsProblem(Log.ERROR, - "Package " + p.name + " was user " - + p.sharedUser + " but is now " + sharedUser - + "; I am not changing its files so it will probably fail!"); - p.sharedUser.packages.remove(p); - } else if (p.userId != sharedUser.userId) { - reportSettingsProblem(Log.ERROR, - "Package " + p.name + " was user id " + p.userId - + " but is now user " + sharedUser - + " with id " + sharedUser.userId - + "; I am not changing its files so it will probably fail!"); - } - - sharedUser.packages.add(p); - p.sharedUser = sharedUser; - p.userId = sharedUser.userId; - } - } + } - /* - * Update the shared user setting when a package using - * specifying the shared user id is removed. The gids - * associated with each permission of the deleted package - * are removed from the shared user's gid list only if its - * not in use by other permissions of packages in the - * shared user setting. - */ - private void updateSharedUserPermsLP(PackageSetting deletedPs, int[] globalGids) { - if ( (deletedPs == null) || (deletedPs.pkg == null)) { - Slog.i(TAG, "Trying to update info for null package. Just ignoring"); - return; - } - // No sharedUserId - if (deletedPs.sharedUser == null) { - return; - } - SharedUserSetting sus = deletedPs.sharedUser; - // Update permissions - for (String eachPerm: deletedPs.pkg.requestedPermissions) { - boolean used = false; - if (!sus.grantedPermissions.contains (eachPerm)) { + /* package */static String getTempContainerId() { + int tmpIdx = 1; + String list[] = PackageHelper.getSecureContainerList(); + if (list != null) { + for (final String name : list) { + // Ignore null and non-temporary container entries + if (name == null || !name.startsWith(mTempContainerPrefix)) { continue; } - for (PackageSetting pkg:sus.packages) { - if (pkg.pkg != null && - !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) && - pkg.pkg.requestedPermissions.contains(eachPerm)) { - used = true; - break; - } - } - if (!used) { - // can safely delete this permission from list - sus.grantedPermissions.remove(eachPerm); - } - } - // Update gids - int newGids[] = globalGids; - for (String eachPerm : sus.grantedPermissions) { - BasePermission bp = mPermissions.get(eachPerm); - if (bp != null) { - newGids = appendInts(newGids, bp.gids); - } - } - sus.gids = newGids; - } - private int removePackageLP(String name) { - PackageSetting p = mPackages.get(name); - if (p != null) { - mPackages.remove(name); - if (p.sharedUser != null) { - p.sharedUser.packages.remove(p); - if (p.sharedUser.packages.size() == 0) { - mSharedUsers.remove(p.sharedUser.name); - removeUserIdLP(p.sharedUser.userId); - return p.sharedUser.userId; + String subStr = name.substring(mTempContainerPrefix.length()); + try { + int cid = Integer.parseInt(subStr); + if (cid >= tmpIdx) { + tmpIdx = cid + 1; } - } else { - removeUserIdLP(p.userId); - return p.userId; - } - } - return -1; - } - - private void replacePackageLP(String name, PackageSetting newp) { - PackageSetting p = mPackages.get(name); - if (p != null) { - if (p.sharedUser != null) { - p.sharedUser.packages.remove(p); - p.sharedUser.packages.add(newp); - } else { - replaceUserIdLP(p.userId, newp); - } - } - mPackages.put(name, newp); - } - - private boolean addUserIdLP(int uid, Object obj, Object name) { - if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) { - return false; - } - - if (uid >= FIRST_APPLICATION_UID) { - int N = mUserIds.size(); - final int index = uid - FIRST_APPLICATION_UID; - while (index >= N) { - mUserIds.add(null); - N++; - } - if (mUserIds.get(index) != null) { - reportSettingsProblem(Log.ERROR, - "Adding duplicate user id: " + uid - + " name=" + name); - return false; - } - mUserIds.set(index, obj); - } else { - if (mOtherUserIds.get(uid) != null) { - reportSettingsProblem(Log.ERROR, - "Adding duplicate shared id: " + uid - + " name=" + name); - return false; - } - mOtherUserIds.put(uid, obj); - } - return true; - } - - public Object getUserIdLP(int uid) { - if (uid >= FIRST_APPLICATION_UID) { - int N = mUserIds.size(); - final int index = uid - FIRST_APPLICATION_UID; - return index < N ? mUserIds.get(index) : null; - } else { - return mOtherUserIds.get(uid); - } - } - - private Set<String> findPackagesWithFlag(int flag) { - Set<String> ret = new HashSet<String>(); - for (PackageSetting ps : mPackages.values()) { - // Has to match atleast all the flag bits set on flag - if ((ps.pkgFlags & flag) == flag) { - ret.add(ps.name); + } catch (NumberFormatException e) { } } - return ret; } + return mTempContainerPrefix + tmpIdx; + } - private void removeUserIdLP(int uid) { - if (uid >= FIRST_APPLICATION_UID) { - int N = mUserIds.size(); - final int index = uid - FIRST_APPLICATION_UID; - if (index < N) mUserIds.set(index, null); - } else { - mOtherUserIds.remove(uid); - } + /* + * Update media status on PackageManager. + */ + public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) { + int callingUid = Binder.getCallingUid(); + if (callingUid != 0 && callingUid != Process.SYSTEM_UID) { + throw new SecurityException("Media status can only be updated by the system"); } - - private void replaceUserIdLP(int uid, Object obj) { - if (uid >= FIRST_APPLICATION_UID) { - int N = mUserIds.size(); - final int index = uid - FIRST_APPLICATION_UID; - if (index < N) mUserIds.set(index, obj); - } else { - mOtherUserIds.put(uid, obj); - } - } - - void writeStoppedLP() { - // Keep the old stopped packages around until we know the new ones have - // been successfully written. - if (mStoppedPackagesFilename.exists()) { - // Presence of backup settings file indicates that we failed - // to persist packages earlier. So preserve the older - // backup for future reference since the current packages - // might have been corrupted. - if (!mBackupStoppedPackagesFilename.exists()) { - if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) { - Log.wtf(TAG, "Unable to backup package manager stopped packages, " - + "current changes will be lost at reboot"); - return; - } - } else { - mStoppedPackagesFilename.delete(); - Slog.w(TAG, "Preserving older stopped packages backup"); - } - } - - try { - FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename); - BufferedOutputStream str = new BufferedOutputStream(fstr); - - //XmlSerializer serializer = XmlUtils.serializerInstance(); - XmlSerializer serializer = new FastXmlSerializer(); - serializer.setOutput(str, "utf-8"); - serializer.startDocument(null, true); - serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - - serializer.startTag(null, "stopped-packages"); - - for (PackageSetting pkg : mPackages.values()) { - if (pkg.stopped) { - serializer.startTag(null, "pkg"); - serializer.attribute(null, "name", pkg.name); - if (pkg.notLaunched) { - serializer.attribute(null, "nl", "1"); - } - serializer.endTag(null, "pkg"); - } - } - - serializer.endTag(null, "stopped-packages"); - - serializer.endDocument(); - - str.flush(); - FileUtils.sync(fstr); - str.close(); - - // New settings successfully written, old ones are no longer - // needed. - mBackupStoppedPackagesFilename.delete(); - FileUtils.setPermissions(mStoppedPackagesFilename.toString(), - FileUtils.S_IRUSR|FileUtils.S_IWUSR - |FileUtils.S_IRGRP|FileUtils.S_IWGRP - |FileUtils.S_IROTH, - -1, -1); - - // Done, all is good! + // reader; this apparently protects mMediaMounted, but should probably + // be a different lock in that case. + synchronized (mPackages) { + Log.i(TAG, "Updating external media status from " + + (mMediaMounted ? "mounted" : "unmounted") + " to " + + (mediaStatus ? "mounted" : "unmounted")); + if (DEBUG_SD_INSTALL) + Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + mediaStatus + + ", mMediaMounted=" + mMediaMounted); + if (mediaStatus == mMediaMounted) { + final Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1 + : 0, -1); + mHandler.sendMessage(msg); return; - - } catch(java.io.IOException e) { - Log.wtf(TAG, "Unable to write package manager stopped packages, " - + " current changes will be lost at reboot", e); - } - - // Clean up partially written files - if (mStoppedPackagesFilename.exists()) { - if (!mStoppedPackagesFilename.delete()) { - Log.i(TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename); - } } + mMediaMounted = mediaStatus; } - - // Note: assumed "stopped" field is already cleared in all packages. - void readStoppedLP() { - FileInputStream str = null; - if (mBackupStoppedPackagesFilename.exists()) { - try { - str = new FileInputStream(mBackupStoppedPackagesFilename); - mReadMessages.append("Reading from backup stopped packages file\n"); - reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file"); - if (mSettingsFilename.exists()) { - // If both the backup and normal file exist, we - // ignore the normal one since it might have been - // corrupted. - Slog.w(TAG, "Cleaning up stopped packages file " - + mStoppedPackagesFilename); - mStoppedPackagesFilename.delete(); - } - } catch (java.io.IOException e) { - // We'll try for the normal settings file. - } + // Queue up an async operation since the package installation may take a + // little while. + mHandler.post(new Runnable() { + public void run() { + // TODO fix this; this does nothing. + mHandler.removeCallbacks(this); + updateExternalMediaStatusInner(mediaStatus, reportStatus); } + }); + } - try { - if (str == null) { - if (!mStoppedPackagesFilename.exists()) { - mReadMessages.append("No stopped packages file found\n"); - reportSettingsProblem(Log.INFO, "No stopped packages file file; " - + "assuming all started"); - // At first boot, make sure no packages are stopped. - // We usually want to have third party apps initialize - // in the stopped state, but not at first boot. - for (PackageSetting pkg : mPackages.values()) { - pkg.stopped = false; - pkg.notLaunched = false; - } - return; - } - str = new FileInputStream(mStoppedPackagesFilename); - } - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(str, null); - - int type; - while ((type=parser.next()) != XmlPullParser.START_TAG - && type != XmlPullParser.END_DOCUMENT) { - ; - } - - if (type != XmlPullParser.START_TAG) { - mReadMessages.append("No start tag found in stopped packages file\n"); - reportSettingsProblem(Log.WARN, - "No start tag found in package manager stopped packages"); - return; - } - - int outerDepth = parser.getDepth(); - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { + /* + * Collect information of applications on external media, map them against + * existing containers and update information based on current mount status. + * Please note that we always have to report status if reportStatus has been + * set to true especially when unloading packages. + */ + private void updateExternalMediaStatusInner(boolean mediaStatus, boolean reportStatus) { + // Collection of uids + int uidArr[] = null; + // Collection of stale containers + HashSet<String> removeCids = new HashSet<String>(); + // Collection of packages on external media with valid containers. + HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>(); + // Get list of secure containers. + final String list[] = PackageHelper.getSecureContainerList(); + if (list == null || list.length == 0) { + Log.i(TAG, "No secure containers on sdcard"); + } else { + // Process list of secure containers and categorize them + // as active or stale based on their package internal state. + int uidList[] = new int[list.length]; + int num = 0; + // reader + synchronized (mPackages) { + for (String cid : list) { + SdInstallArgs args = new SdInstallArgs(cid); + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Processing container " + cid); + String pkgName = args.getPackageName(); + if (pkgName == null) { + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Container : " + cid + " stale"); + removeCids.add(cid); continue; } - - String tagName = parser.getName(); - if (tagName.equals("pkg")) { - String name = parser.getAttributeValue(null, "name"); - PackageSetting ps = mPackages.get(name); - if (ps != null) { - ps.stopped = true; - if ("1".equals(parser.getAttributeValue(null, "nl"))) { - ps.notLaunched = true; - } - } else { - Slog.w(TAG, "No package known for stopped package: " + name); + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Looking for pkg : " + pkgName); + PackageSetting ps = mSettings.mPackages.get(pkgName); + // The package status is changed only if the code path + // matches between settings and the container id. + if (ps != null && ps.codePathString != null + && ps.codePathString.equals(args.getCodePath())) { + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Container : " + cid + " corresponds to pkg : " + pkgName + + " at code path: " + ps.codePathString); + // We do have a valid package installed on sdcard + processCids.put(args, ps.codePathString); + int uid = ps.userId; + if (uid != -1) { + uidList[num++] = uid; } - XmlUtils.skipCurrentTag(parser); } else { - Slog.w(TAG, "Unknown element under <stopped-packages>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); + // Stale container on sdcard. Just delete + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Container : " + cid + " stale"); + removeCids.add(cid); } } - - str.close(); - - } catch(XmlPullParserException e) { - mReadMessages.append("Error reading: " + e.toString()); - reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e); - Log.wtf(TAG, "Error reading package manager stopped packages", e); - - } catch(java.io.IOException e) { - mReadMessages.append("Error reading: " + e.toString()); - reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); - Log.wtf(TAG, "Error reading package manager stopped packages", e); - } - } - - void writeLP() { - //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024); - // Keep the old settings around until we know the new ones have - // been successfully written. - if (mSettingsFilename.exists()) { - // Presence of backup settings file indicates that we failed - // to persist settings earlier. So preserve the older - // backup for future reference since the current settings - // might have been corrupted. - if (!mBackupSettingsFilename.exists()) { - if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) { - Log.wtf(TAG, "Unable to backup package manager settings, " - + " current changes will be lost at reboot"); - return; + if (num > 0) { + // Sort uid list + Arrays.sort(uidList, 0, num); + // Throw away duplicates + uidArr = new int[num]; + uidArr[0] = uidList[0]; + int di = 0; + for (int i = 1; i < num; i++) { + if (uidList[i - 1] != uidList[i]) { + uidArr[di++] = uidList[i]; } - } else { - mSettingsFilename.delete(); - Slog.w(TAG, "Preserving older settings backup"); } } - - mPastSignatures.clear(); - - try { - FileOutputStream fstr = new FileOutputStream(mSettingsFilename); - BufferedOutputStream str = new BufferedOutputStream(fstr); - - //XmlSerializer serializer = XmlUtils.serializerInstance(); - XmlSerializer serializer = new FastXmlSerializer(); - serializer.setOutput(str, "utf-8"); - serializer.startDocument(null, true); - serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - - serializer.startTag(null, "packages"); - - serializer.startTag(null, "last-platform-version"); - serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform)); - serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform)); - serializer.endTag(null, "last-platform-version"); - - serializer.startTag(null, "permission-trees"); - for (BasePermission bp : mPermissionTrees.values()) { - writePermission(serializer, bp); - } - serializer.endTag(null, "permission-trees"); - - serializer.startTag(null, "permissions"); - for (BasePermission bp : mPermissions.values()) { - writePermission(serializer, bp); - } - serializer.endTag(null, "permissions"); - - for (PackageSetting pkg : mPackages.values()) { - writePackage(serializer, pkg); - } - - for (PackageSetting pkg : mDisabledSysPackages.values()) { - writeDisabledSysPackage(serializer, pkg); - } - - serializer.startTag(null, "preferred-activities"); - for (PreferredActivity pa : mPreferredActivities.filterSet()) { - serializer.startTag(null, "item"); - pa.writeToXml(serializer); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "preferred-activities"); - - for (SharedUserSetting usr : mSharedUsers.values()) { - serializer.startTag(null, "shared-user"); - serializer.attribute(null, "name", usr.name); - serializer.attribute(null, "userId", - Integer.toString(usr.userId)); - usr.signatures.writeXml(serializer, "sigs", mPastSignatures); - serializer.startTag(null, "perms"); - for (String name : usr.grantedPermissions) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "perms"); - serializer.endTag(null, "shared-user"); - } - - if (mPackagesToBeCleaned.size() > 0) { - for (int i=0; i<mPackagesToBeCleaned.size(); i++) { - serializer.startTag(null, "cleaning-package"); - serializer.attribute(null, "name", mPackagesToBeCleaned.get(i)); - serializer.endTag(null, "cleaning-package"); - } - } - - if (mRenamedPackages.size() > 0) { - for (HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) { - serializer.startTag(null, "renamed-package"); - serializer.attribute(null, "new", e.getKey()); - serializer.attribute(null, "old", e.getValue()); - serializer.endTag(null, "renamed-package"); - } - } - - serializer.endTag(null, "packages"); - - serializer.endDocument(); - - str.flush(); - FileUtils.sync(fstr); - str.close(); - - // New settings successfully written, old ones are no longer - // needed. - mBackupSettingsFilename.delete(); - FileUtils.setPermissions(mSettingsFilename.toString(), - FileUtils.S_IRUSR|FileUtils.S_IWUSR - |FileUtils.S_IRGRP|FileUtils.S_IWGRP - |FileUtils.S_IROTH, - -1, -1); - - // Write package list file now, use a JournaledFile. - // - File tempFile = new File(mPackageListFilename.toString() + ".tmp"); - JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile); - - fstr = new FileOutputStream(journal.chooseForWrite()); - str = new BufferedOutputStream(fstr); - try { - StringBuilder sb = new StringBuilder(); - for (PackageSetting pkg : mPackages.values()) { - ApplicationInfo ai = pkg.pkg.applicationInfo; - String dataPath = ai.dataDir; - boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; - - // Avoid any application that has a space in its path - // or that is handled by the system. - if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID) - continue; - - // we store on each line the following information for now: - // - // pkgName - package name - // userId - application-specific user id - // debugFlag - 0 or 1 if the package is debuggable. - // dataPath - path to package's data path - // - // NOTE: We prefer not to expose all ApplicationInfo flags for now. - // - // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS - // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES: - // system/core/run-as/run-as.c - // - sb.setLength(0); - sb.append(ai.packageName); - sb.append(" "); - sb.append((int)ai.uid); - sb.append(isDebug ? " 1 " : " 0 "); - sb.append(dataPath); - sb.append("\n"); - str.write(sb.toString().getBytes()); - } - str.flush(); - FileUtils.sync(fstr); - str.close(); - journal.commit(); - } - catch (Exception e) { - journal.rollback(); - } - - FileUtils.setPermissions(mPackageListFilename.toString(), - FileUtils.S_IRUSR|FileUtils.S_IWUSR - |FileUtils.S_IRGRP|FileUtils.S_IWGRP - |FileUtils.S_IROTH, - -1, -1); - - writeStoppedLP(); - - return; - - } catch(XmlPullParserException e) { - Log.wtf(TAG, "Unable to write package manager settings, " - + "current changes will be lost at reboot", e); - } catch(java.io.IOException e) { - Log.wtf(TAG, "Unable to write package manager settings, " - + "current changes will be lost at reboot", e); - } - // Clean up partially written files - if (mSettingsFilename.exists()) { - if (!mSettingsFilename.delete()) { - Log.wtf(TAG, "Failed to clean up mangled file: " + mSettingsFilename); - } - } - //Debug.stopMethodTracing(); - } - - void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg) - throws java.io.IOException { - serializer.startTag(null, "updated-package"); - serializer.attribute(null, "name", pkg.name); - if (pkg.realName != null) { - serializer.attribute(null, "realName", pkg.realName); - } - serializer.attribute(null, "codePath", pkg.codePathString); - serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp)); - serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime)); - serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime)); - serializer.attribute(null, "version", String.valueOf(pkg.versionCode)); - if (!pkg.resourcePathString.equals(pkg.codePathString)) { - serializer.attribute(null, "resourcePath", pkg.resourcePathString); - } - if (pkg.nativeLibraryPathString != null) { - serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); - } - if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", - Integer.toString(pkg.userId)); - } else { - serializer.attribute(null, "sharedUserId", - Integer.toString(pkg.userId)); - } - serializer.startTag(null, "perms"); - if (pkg.sharedUser == null) { - // If this is a shared user, the permissions will - // be written there. We still need to write an - // empty permissions list so permissionsFixed will - // be set. - for (final String name : pkg.grantedPermissions) { - BasePermission bp = mPermissions.get(name); - if (bp != null) { - // We only need to write signature or system permissions but this wont - // match the semantics of grantedPermissions. So write all permissions. - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - } - } - serializer.endTag(null, "perms"); - serializer.endTag(null, "updated-package"); - } - - void writePackage(XmlSerializer serializer, final PackageSetting pkg) - throws java.io.IOException { - serializer.startTag(null, "package"); - serializer.attribute(null, "name", pkg.name); - if (pkg.realName != null) { - serializer.attribute(null, "realName", pkg.realName); - } - serializer.attribute(null, "codePath", pkg.codePathString); - if (!pkg.resourcePathString.equals(pkg.codePathString)) { - serializer.attribute(null, "resourcePath", pkg.resourcePathString); - } - if (pkg.nativeLibraryPathString != null) { - serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); - } - serializer.attribute(null, "flags", - Integer.toString(pkg.pkgFlags)); - serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp)); - serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime)); - serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime)); - serializer.attribute(null, "version", String.valueOf(pkg.versionCode)); - if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", - Integer.toString(pkg.userId)); - } else { - serializer.attribute(null, "sharedUserId", - Integer.toString(pkg.userId)); - } - if (pkg.uidError) { - serializer.attribute(null, "uidError", "true"); - } - if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { - serializer.attribute(null, "enabled", - pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED - ? "true" : "false"); - } - if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) { - serializer.attribute(null, "installStatus", "false"); - } - if (pkg.installerPackageName != null) { - serializer.attribute(null, "installer", pkg.installerPackageName); - } - pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); - if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { - serializer.startTag(null, "perms"); - if (pkg.sharedUser == null) { - // If this is a shared user, the permissions will - // be written there. We still need to write an - // empty permissions list so permissionsFixed will - // be set. - for (final String name : pkg.grantedPermissions) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - } - serializer.endTag(null, "perms"); - } - if (pkg.disabledComponents.size() > 0) { - serializer.startTag(null, "disabled-components"); - for (final String name : pkg.disabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "disabled-components"); - } - if (pkg.enabledComponents.size() > 0) { - serializer.startTag(null, "enabled-components"); - for (final String name : pkg.enabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "enabled-components"); - } - - serializer.endTag(null, "package"); - } - - void writePermission(XmlSerializer serializer, BasePermission bp) - throws XmlPullParserException, java.io.IOException { - if (bp.type != BasePermission.TYPE_BUILTIN - && bp.sourcePackage != null) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", bp.name); - serializer.attribute(null, "package", bp.sourcePackage); - if (bp.protectionLevel != - PermissionInfo.PROTECTION_NORMAL) { - serializer.attribute(null, "protection", - Integer.toString(bp.protectionLevel)); - } - if (DEBUG_SETTINGS) Log.v(TAG, - "Writing perm: name=" + bp.name + " type=" + bp.type); - if (bp.type == BasePermission.TYPE_DYNAMIC) { - PermissionInfo pi = bp.perm != null ? bp.perm.info - : bp.pendingInfo; - if (pi != null) { - serializer.attribute(null, "type", "dynamic"); - if (pi.icon != 0) { - serializer.attribute(null, "icon", - Integer.toString(pi.icon)); - } - if (pi.nonLocalizedLabel != null) { - serializer.attribute(null, "label", - pi.nonLocalizedLabel.toString()); - } - } - } - serializer.endTag(null, "item"); - } - } - - String getReadMessagesLP() { - return mReadMessages.toString(); } - - ArrayList<PackageSetting> getListOfIncompleteInstallPackages() { - HashSet<String> kList = new HashSet<String>(mPackages.keySet()); - Iterator<String> its = kList.iterator(); - ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>(); - while(its.hasNext()) { - String key = its.next(); - PackageSetting ps = mPackages.get(key); - if(ps.getInstallStatus() == PKG_INSTALL_INCOMPLETE) { - ret.add(ps); - } - } - return ret; + // Process packages with valid entries. + if (mediaStatus) { + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Loading packages"); + loadMediaPackages(processCids, uidArr, removeCids); + startCleaningPackages(); + } else { + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Unloading packages"); + unloadMediaPackages(processCids, uidArr, reportStatus); } + } - boolean readLP() { - FileInputStream str = null; - if (mBackupSettingsFilename.exists()) { - try { - str = new FileInputStream(mBackupSettingsFilename); - mReadMessages.append("Reading from backup settings file\n"); - reportSettingsProblem(Log.INFO, "Need to read from backup settings file"); - if (mSettingsFilename.exists()) { - // If both the backup and settings file exist, we - // ignore the settings since it might have been - // corrupted. - Slog.w(TAG, "Cleaning up settings file " + mSettingsFilename); - mSettingsFilename.delete(); - } - } catch (java.io.IOException e) { - // We'll try for the normal settings file. - } - } - - mPastSignatures.clear(); - - try { - if (str == null) { - if (!mSettingsFilename.exists()) { - mReadMessages.append("No settings file found\n"); - reportSettingsProblem(Log.INFO, "No settings file; creating initial state"); - return false; - } - str = new FileInputStream(mSettingsFilename); - } - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(str, null); - - int type; - while ((type=parser.next()) != XmlPullParser.START_TAG - && type != XmlPullParser.END_DOCUMENT) { - ; - } - - if (type != XmlPullParser.START_TAG) { - mReadMessages.append("No start tag found in settings file\n"); - reportSettingsProblem(Log.WARN, "No start tag found in package manager settings"); - Log.wtf(TAG, "No start tag found in package manager settings"); - return false; - } - - int outerDepth = parser.getDepth(); - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("package")) { - readPackageLP(parser); - } else if (tagName.equals("permissions")) { - readPermissionsLP(mPermissions, parser); - } else if (tagName.equals("permission-trees")) { - readPermissionsLP(mPermissionTrees, parser); - } else if (tagName.equals("shared-user")) { - readSharedUserLP(parser); - } else if (tagName.equals("preferred-packages")) { - // no longer used. - } else if (tagName.equals("preferred-activities")) { - readPreferredActivitiesLP(parser); - } else if(tagName.equals("updated-package")) { - readDisabledSysPackageLP(parser); - } else if (tagName.equals("cleaning-package")) { - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - mPackagesToBeCleaned.add(name); - } - } else if (tagName.equals("renamed-package")) { - String nname = parser.getAttributeValue(null, "new"); - String oname = parser.getAttributeValue(null, "old"); - if (nname != null && oname != null) { - mRenamedPackages.put(nname, oname); - } - } else if (tagName.equals("last-platform-version")) { - mInternalSdkPlatform = mExternalSdkPlatform = 0; - try { - String internal = parser.getAttributeValue(null, "internal"); - if (internal != null) { - mInternalSdkPlatform = Integer.parseInt(internal); - } - String external = parser.getAttributeValue(null, "external"); - if (external != null) { - mExternalSdkPlatform = Integer.parseInt(external); - } - } catch (NumberFormatException e) { - } - } else { - Slog.w(TAG, "Unknown element under <packages>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - - str.close(); - - } catch(XmlPullParserException e) { - mReadMessages.append("Error reading: " + e.toString()); - reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); - Log.wtf(TAG, "Error reading package manager settings", e); - - } catch(java.io.IOException e) { - mReadMessages.append("Error reading: " + e.toString()); - reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); - Log.wtf(TAG, "Error reading package manager settings", e); - - } - - int N = mPendingPackages.size(); - for (int i=0; i<N; i++) { - final PendingPackage pp = mPendingPackages.get(i); - Object idObj = getUserIdLP(pp.sharedId); - if (idObj != null && idObj instanceof SharedUserSetting) { - PackageSetting p = getPackageLP(pp.name, null, pp.realName, - (SharedUserSetting) idObj, pp.codePath, pp.resourcePath, - pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true); - if (p == null) { - reportSettingsProblem(Log.WARN, "Unable to create application package for " - + pp.name); - continue; - } - p.copyFrom(pp); - } else if (idObj != null) { - String msg = "Bad package setting: package " + pp.name - + " has shared uid " + pp.sharedId - + " that is not a shared uid\n"; - mReadMessages.append(msg); - reportSettingsProblem(Log.ERROR, msg); - } else { - String msg = "Bad package setting: package " + pp.name - + " has shared uid " + pp.sharedId - + " that is not defined\n"; - mReadMessages.append(msg); - reportSettingsProblem(Log.ERROR, msg); - } + private void sendResourcesChangedBroadcast(boolean mediaStatus, ArrayList<String> pkgList, + int uidArr[], IIntentReceiver finishedReceiver) { + int size = pkgList.size(); + if (size > 0) { + // Send broadcasts here + Bundle extras = new Bundle(); + extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList + .toArray(new String[size])); + if (uidArr != null) { + extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); } - mPendingPackages.clear(); - - readStoppedLP(); - - mReadMessages.append("Read completed successfully: " - + mPackages.size() + " packages, " - + mSharedUsers.size() + " shared uids\n"); - - return true; + String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE + : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; + sendPackageBroadcast(action, null, extras, null, finishedReceiver); } + } - private int readInt(XmlPullParser parser, String ns, String name, - int defValue) { - String v = parser.getAttributeValue(ns, name); + /* + * Look at potentially valid container ids from processCids If package + * information doesn't match the one on record or package scanning fails, + * the cid is added to list of removeCids. We currently don't delete stale + * containers. + */ + private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[], + HashSet<String> removeCids) { + ArrayList<String> pkgList = new ArrayList<String>(); + Set<SdInstallArgs> keys = processCids.keySet(); + boolean doGc = false; + for (SdInstallArgs args : keys) { + String codePath = processCids.get(args); + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Loading container : " + args.cid); + int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR; try { - if (v == null) { - return defValue; - } - return Integer.parseInt(v); - } catch (NumberFormatException e) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: attribute " + - name + " has bad integer value " + v + " at " - + parser.getPositionDescription()); - } - return defValue; - } - - private void readPermissionsLP(HashMap<String, BasePermission> out, - XmlPullParser parser) - throws IOException, XmlPullParserException { - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { + // Make sure there are no container errors first. + if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) { + Slog.e(TAG, "Failed to mount cid : " + args.cid + + " when installing from sdcard"); continue; } - - String tagName = parser.getName(); - if (tagName.equals("item")) { - String name = parser.getAttributeValue(null, "name"); - String sourcePackage = parser.getAttributeValue(null, "package"); - String ptype = parser.getAttributeValue(null, "type"); - if (name != null && sourcePackage != null) { - boolean dynamic = "dynamic".equals(ptype); - BasePermission bp = new BasePermission(name, sourcePackage, - dynamic - ? BasePermission.TYPE_DYNAMIC - : BasePermission.TYPE_NORMAL); - bp.protectionLevel = readInt(parser, null, "protection", - PermissionInfo.PROTECTION_NORMAL); - if (dynamic) { - PermissionInfo pi = new PermissionInfo(); - pi.packageName = sourcePackage.intern(); - pi.name = name.intern(); - pi.icon = readInt(parser, null, "icon", 0); - pi.nonLocalizedLabel = parser.getAttributeValue( - null, "label"); - pi.protectionLevel = bp.protectionLevel; - bp.pendingInfo = pi; - } - out.put(bp.name, bp); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: permissions has" - + " no name at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element reading permissions: " - + parser.getName() + " at " - + parser.getPositionDescription()); - } - XmlUtils.skipCurrentTag(parser); - } - } - - private void readDisabledSysPackageLP(XmlPullParser parser) - throws XmlPullParserException, IOException { - String name = parser.getAttributeValue(null, "name"); - String realName = parser.getAttributeValue(null, "realName"); - String codePathStr = parser.getAttributeValue(null, "codePath"); - String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); - String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); - if (resourcePathStr == null) { - resourcePathStr = codePathStr; - } - String version = parser.getAttributeValue(null, "version"); - int versionCode = 0; - if (version != null) { - try { - versionCode = Integer.parseInt(version); - } catch (NumberFormatException e) { - } - } - - int pkgFlags = 0; - pkgFlags |= ApplicationInfo.FLAG_SYSTEM; - PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr), - new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags); - String timeStampStr = parser.getAttributeValue(null, "ft"); - if (timeStampStr != null) { - try { - long timeStamp = Long.parseLong(timeStampStr, 16); - ps.setTimeStamp(timeStamp); - } catch (NumberFormatException e) { - } - } else { - timeStampStr = parser.getAttributeValue(null, "ts"); - if (timeStampStr != null) { - try { - long timeStamp = Long.parseLong(timeStampStr); - ps.setTimeStamp(timeStamp); - } catch (NumberFormatException e) { - } - } - } - timeStampStr = parser.getAttributeValue(null, "it"); - if (timeStampStr != null) { - try { - ps.firstInstallTime = Long.parseLong(timeStampStr, 16); - } catch (NumberFormatException e) { - } - } - timeStampStr = parser.getAttributeValue(null, "ut"); - if (timeStampStr != null) { - try { - ps.lastUpdateTime = Long.parseLong(timeStampStr, 16); - } catch (NumberFormatException e) { - } - } - String idStr = parser.getAttributeValue(null, "userId"); - ps.userId = idStr != null ? Integer.parseInt(idStr) : 0; - if(ps.userId <= 0) { - String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); - ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; - } - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { + // Check code path here. + if (codePath == null || !codePath.equals(args.getCodePath())) { + Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath() + + " does not match one in settings " + codePath); continue; } - - String tagName = parser.getName(); - if (tagName.equals("perms")) { - readGrantedPermissionsLP(parser, - ps.grantedPermissions); - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <updated-package>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - mDisabledSysPackages.put(name, ps); - } - - private void readPackageLP(XmlPullParser parser) - throws XmlPullParserException, IOException { - String name = null; - String realName = null; - String idStr = null; - String sharedIdStr = null; - String codePathStr = null; - String resourcePathStr = null; - String nativeLibraryPathStr = null; - String systemStr = null; - String installerPackageName = null; - String uidError = null; - int pkgFlags = 0; - long timeStamp = 0; - long firstInstallTime = 0; - long lastUpdateTime = 0; - PackageSettingBase packageSetting = null; - String version = null; - int versionCode = 0; - try { - name = parser.getAttributeValue(null, "name"); - realName = parser.getAttributeValue(null, "realName"); - idStr = parser.getAttributeValue(null, "userId"); - uidError = parser.getAttributeValue(null, "uidError"); - sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); - codePathStr = parser.getAttributeValue(null, "codePath"); - resourcePathStr = parser.getAttributeValue(null, "resourcePath"); - nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); - version = parser.getAttributeValue(null, "version"); - if (version != null) { - try { - versionCode = Integer.parseInt(version); - } catch (NumberFormatException e) { - } - } - installerPackageName = parser.getAttributeValue(null, "installer"); - - systemStr = parser.getAttributeValue(null, "flags"); - if (systemStr != null) { - try { - pkgFlags = Integer.parseInt(systemStr); - } catch (NumberFormatException e) { - } - } else { - // For backward compatibility - systemStr = parser.getAttributeValue(null, "system"); - if (systemStr != null) { - pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM : 0; - } else { - // Old settings that don't specify system... just treat - // them as system, good enough. - pkgFlags |= ApplicationInfo.FLAG_SYSTEM; - } - } - String timeStampStr = parser.getAttributeValue(null, "ft"); - if (timeStampStr != null) { - try { - timeStamp = Long.parseLong(timeStampStr, 16); - } catch (NumberFormatException e) { - } - } else { - timeStampStr = parser.getAttributeValue(null, "ts"); - if (timeStampStr != null) { - try { - timeStamp = Long.parseLong(timeStampStr); - } catch (NumberFormatException e) { + // Parse package + int parseFlags = PackageParser.PARSE_ON_SDCARD | mDefParseFlags; + doGc = true; + synchronized (mInstallLock) { + final PackageParser.Package pkg = scanPackageLI(new File(codePath), parseFlags, + 0, 0); + // Scan the package + if (pkg != null) { + /* + * TODO why is the lock being held? doPostInstall is + * called in other places without the lock. This needs + * to be straightened out. + */ + // writer + synchronized (mPackages) { + retCode = PackageManager.INSTALL_SUCCEEDED; + pkgList.add(pkg.packageName); + // Post process args + args.doPostInstall(PackageManager.INSTALL_SUCCEEDED); } - } - } - timeStampStr = parser.getAttributeValue(null, "it"); - if (timeStampStr != null) { - try { - firstInstallTime = Long.parseLong(timeStampStr, 16); - } catch (NumberFormatException e) { - } - } - timeStampStr = parser.getAttributeValue(null, "ut"); - if (timeStampStr != null) { - try { - lastUpdateTime = Long.parseLong(timeStampStr, 16); - } catch (NumberFormatException e) { - } - } - if (DEBUG_SETTINGS) Log.v(TAG, "Reading package: " + name - + " userId=" + idStr + " sharedUserId=" + sharedIdStr); - int userId = idStr != null ? Integer.parseInt(idStr) : 0; - if (resourcePathStr == null) { - resourcePathStr = codePathStr; - } - if (realName != null) { - realName = realName.intern(); - } - if (name == null) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <package> has no name at " - + parser.getPositionDescription()); - } else if (codePathStr == null) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <package> has no codePath at " - + parser.getPositionDescription()); - } else if (userId > 0) { - packageSetting = addPackageLP(name.intern(), realName, new File(codePathStr), - new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode, - pkgFlags); - if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name - + ": userId=" + userId + " pkg=" + packageSetting); - if (packageSetting == null) { - reportSettingsProblem(Log.ERROR, - "Failure adding uid " + userId - + " while parsing settings at " - + parser.getPositionDescription()); - } else { - packageSetting.setTimeStamp(timeStamp); - packageSetting.firstInstallTime = firstInstallTime; - packageSetting.lastUpdateTime = lastUpdateTime; - } - } else if (sharedIdStr != null) { - userId = sharedIdStr != null - ? Integer.parseInt(sharedIdStr) : 0; - if (userId > 0) { - packageSetting = new PendingPackage(name.intern(), realName, - new File(codePathStr), new File(resourcePathStr), - nativeLibraryPathStr, userId, versionCode, pkgFlags); - packageSetting.setTimeStamp(timeStamp); - packageSetting.firstInstallTime = firstInstallTime; - packageSetting.lastUpdateTime = lastUpdateTime; - mPendingPackages.add((PendingPackage) packageSetting); - if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name - + ": sharedUserId=" + userId + " pkg=" - + packageSetting); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad sharedId " + sharedIdStr - + " at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad userId " + idStr + " at " - + parser.getPositionDescription()); - } - } catch (NumberFormatException e) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad userId " + idStr + " at " - + parser.getPositionDescription()); - } - if (packageSetting != null) { - packageSetting.uidError = "true".equals(uidError); - packageSetting.installerPackageName = installerPackageName; - packageSetting.nativeLibraryPathString = nativeLibraryPathStr; - final String enabledStr = parser.getAttributeValue(null, "enabled"); - if (enabledStr != null) { - if (enabledStr.equalsIgnoreCase("true")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED; - } else if (enabledStr.equalsIgnoreCase("false")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED; - } else if (enabledStr.equalsIgnoreCase("default")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad enabled value: " + idStr - + " at " + parser.getPositionDescription()); - } - } else { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; - } - final String installStatusStr = parser.getAttributeValue(null, "installStatus"); - if (installStatusStr != null) { - if (installStatusStr.equalsIgnoreCase("false")) { - packageSetting.installStatus = PKG_INSTALL_INCOMPLETE; } else { - packageSetting.installStatus = PKG_INSTALL_COMPLETE; + Slog.i(TAG, "Failed to install pkg from " + codePath + " from sdcard"); } } - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("disabled-components")) { - readDisabledComponentsLP(packageSetting, parser); - } else if (tagName.equals("enabled-components")) { - readEnabledComponentsLP(packageSetting, parser); - } else if (tagName.equals("sigs")) { - packageSetting.signatures.readXml(parser, mPastSignatures); - } else if (tagName.equals("perms")) { - readGrantedPermissionsLP(parser, - packageSetting.grantedPermissions); - packageSetting.permissionsFixed = true; - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <package>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } + } finally { + if (retCode != PackageManager.INSTALL_SUCCEEDED) { + // Don't destroy container here. Wait till gc clears things + // up. + removeCids.add(args.cid); } - } else { - XmlUtils.skipCurrentTag(parser); } } - - private void readDisabledComponentsLP(PackageSettingBase packageSetting, - XmlPullParser parser) - throws IOException, XmlPullParserException { - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("item")) { - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - packageSetting.disabledComponents.add(name.intern()); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <disabled-components> has" - + " no name at " + parser.getPositionDescription()); - } + // writer + synchronized (mPackages) { + // If the platform SDK has changed since the last time we booted, + // we need to re-grant app permission to catch any new ones that + // appear. This is really a hack, and means that apps can in some + // cases get permissions that the user didn't initially explicitly + // allow... it would be nice to have some better way to handle + // this situation. + final boolean regrantPermissions = mSettings.mExternalSdkPlatform != mSdkVersion; + if (regrantPermissions) + Slog.i(TAG, "Platform changed from " + mSettings.mExternalSdkPlatform + " to " + + mSdkVersion + "; regranting permissions for external storage"); + mSettings.mExternalSdkPlatform = mSdkVersion; + + // Make sure group IDs have been assigned, and any permission + // changes in other apps are accounted for + updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions); + // can downgrade to reader + // Persist settings + mSettings.writeLPr(); + } + // Send a broadcast to let everyone know we are done processing + if (pkgList.size() > 0) { + sendResourcesChangedBroadcast(true, pkgList, uidArr, null); + } + // Force gc to avoid any stale parser references that we might have. + if (doGc) { + Runtime.getRuntime().gc(); + } + // List stale containers and destroy stale temporary containers. + if (removeCids != null) { + for (String cid : removeCids) { + if (cid.startsWith(mTempContainerPrefix)) { + Log.i(TAG, "Destroying stale temporary container " + cid); + PackageHelper.destroySdDir(cid); } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <disabled-components>: " - + parser.getName()); - } - XmlUtils.skipCurrentTag(parser); - } + Log.w(TAG, "Container " + cid + " is stale"); + } + } } + } - private void readEnabledComponentsLP(PackageSettingBase packageSetting, - XmlPullParser parser) - throws IOException, XmlPullParserException { - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; - } + /* + * Utility method to unload a list of specified containers + */ + private void unloadAllContainers(Set<SdInstallArgs> cidArgs) { + // Just unmount all valid containers. + for (SdInstallArgs arg : cidArgs) { + synchronized (mInstallLock) { + arg.doPostDeleteLI(false); + } + } + } - String tagName = parser.getName(); - if (tagName.equals("item")) { - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - packageSetting.enabledComponents.add(name.intern()); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <enabled-components> has" - + " no name at " + parser.getPositionDescription()); - } + /* + * Unload packages mounted on external media. This involves deleting package + * data from internal structures, sending broadcasts about diabled packages, + * gc'ing to free up references, unmounting all secure containers + * corresponding to packages on external media, and posting a + * UPDATED_MEDIA_STATUS message if status has been requested. Please note + * that we always have to post this message if status has been requested no + * matter what. + */ + private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[], + final boolean reportStatus) { + if (DEBUG_SD_INSTALL) + Log.i(TAG, "unloading media packages"); + ArrayList<String> pkgList = new ArrayList<String>(); + ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>(); + final Set<SdInstallArgs> keys = processCids.keySet(); + for (SdInstallArgs args : keys) { + String pkgName = args.getPackageName(); + if (DEBUG_SD_INSTALL) + Log.i(TAG, "Trying to unload pkg : " + pkgName); + // Delete package internally + PackageRemovedInfo outInfo = new PackageRemovedInfo(); + synchronized (mInstallLock) { + boolean res = deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA, + outInfo, false); + if (res) { + pkgList.add(pkgName); } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <enabled-components>: " - + parser.getName()); + Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName); + failedList.add(args); } - XmlUtils.skipCurrentTag(parser); } } - private void readSharedUserLP(XmlPullParser parser) - throws XmlPullParserException, IOException { - String name = null; - String idStr = null; - int pkgFlags = 0; - SharedUserSetting su = null; - try { - name = parser.getAttributeValue(null, "name"); - idStr = parser.getAttributeValue(null, "userId"); - int userId = idStr != null ? Integer.parseInt(idStr) : 0; - if ("true".equals(parser.getAttributeValue(null, "system"))) { - pkgFlags |= ApplicationInfo.FLAG_SYSTEM; - } - if (name == null) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <shared-user> has no name at " - + parser.getPositionDescription()); - } else if (userId == 0) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: shared-user " - + name + " has bad userId " + idStr + " at " - + parser.getPositionDescription()); - } else { - if ((su=addSharedUserLP(name.intern(), userId, pkgFlags)) == null) { - reportSettingsProblem(Log.ERROR, - "Occurred while parsing settings at " - + parser.getPositionDescription()); - } - } - } catch (NumberFormatException e) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad userId " + idStr + " at " - + parser.getPositionDescription()); - }; - - if (su != null) { - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("sigs")) { - su.signatures.readXml(parser, mPastSignatures); - } else if (tagName.equals("perms")) { - readGrantedPermissionsLP(parser, su.grantedPermissions); - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <shared-user>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } + // reader + synchronized (mPackages) { + // We didn't update the settings after removing each package; + // write them now for all packages. + mSettings.writeLPr(); + } + + // We have to absolutely send UPDATED_MEDIA_STATUS only + // after confirming that all the receivers processed the ordered + // broadcast when packages get disabled, force a gc to clean things up. + // and unload all the containers. + if (pkgList.size() > 0) { + sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() { + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean ordered, boolean sticky) throws RemoteException { + Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, + reportStatus ? 1 : 0, 1, keys); + mHandler.sendMessage(msg); } - - } else { - XmlUtils.skipCurrentTag(parser); - } + }); + } else { + Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1 : 0, -1, + keys); + mHandler.sendMessage(msg); } + } - private void readGrantedPermissionsLP(XmlPullParser parser, - HashSet<String> outPerms) throws IOException, XmlPullParserException { - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("item")) { - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - outPerms.add(name.intern()); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <perms> has" - + " no name at " + parser.getPositionDescription()); - } + public void movePackage(final String packageName, final IPackageMoveObserver observer, + final int flags) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null); + int returnCode = PackageManager.MOVE_SUCCEEDED; + int currFlags = 0; + int newFlags = 0; + // reader + synchronized (mPackages) { + PackageParser.Package pkg = mPackages.get(packageName); + if (pkg == null) { + returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; + } else { + // Disable moving fwd locked apps and system packages + if (pkg.applicationInfo != null && isSystemApp(pkg)) { + Slog.w(TAG, "Cannot move system application"); + returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; + } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) { + Slog.w(TAG, "Cannot move forward locked app."); + returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED; + } else if (pkg.mOperationPending) { + Slog.w(TAG, "Attempt to move package which has pending operations"); + returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING; } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <perms>: " - + parser.getName()); - } - XmlUtils.skipCurrentTag(parser); - } - } - - private void readPreferredActivitiesLP(XmlPullParser parser) - throws XmlPullParserException, IOException { - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG - || type == XmlPullParser.TEXT) { - continue; - } - - String tagName = parser.getName(); - if (tagName.equals("item")) { - PreferredActivity pa = new PreferredActivity(parser); - if (pa.mPref.getParseError() == null) { - mPreferredActivities.addFilter(pa); + // Find install location first + if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 + && (flags & PackageManager.MOVE_INTERNAL) != 0) { + Slog.w(TAG, "Ambigous flags specified for move location."); + returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION; } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <preferred-activity> " - + pa.mPref.getParseError() + " at " - + parser.getPositionDescription()); + newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ? PackageManager.INSTALL_EXTERNAL + : PackageManager.INSTALL_INTERNAL; + currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL + : PackageManager.INSTALL_INTERNAL; + if (newFlags == currFlags) { + Slog.w(TAG, "No move required. Trying to move to same location"); + returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION; + } } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <preferred-activities>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - } - - // Returns -1 if we could not find an available UserId to assign - private int newUserIdLP(Object obj) { - // Let's be stupidly inefficient for now... - final int N = mUserIds.size(); - for (int i=0; i<N; i++) { - if (mUserIds.get(i) == null) { - mUserIds.set(i, obj); - return FIRST_APPLICATION_UID + i; - } - } - - // None left? - if (N >= MAX_APPLICATION_UIDS) { - return -1; - } - - mUserIds.add(obj); - return FIRST_APPLICATION_UID + N; - } - - public PackageSetting getDisabledSystemPkg(String name) { - synchronized(mPackages) { - PackageSetting ps = mDisabledSysPackages.get(name); - return ps; - } - } - - boolean isEnabledLP(ComponentInfo componentInfo, int flags) { - if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - return true; - } - final PackageSetting packageSettings = mPackages.get(componentInfo.packageName); - if (Config.LOGV) { - Log.v(TAG, "isEnabledLock - packageName = " + componentInfo.packageName - + " componentName = " + componentInfo.name); - Log.v(TAG, "enabledComponents: " - + Arrays.toString(packageSettings.enabledComponents.toArray())); - Log.v(TAG, "disabledComponents: " - + Arrays.toString(packageSettings.disabledComponents.toArray())); - } - if (packageSettings == null) { - if (false) { - Log.w(TAG, "WAITING FOR DEBUGGER"); - Debug.waitForDebugger(); - Log.i(TAG, "We will crash!"); - } - return false; - } - if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED - || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled - && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) { - return false; - } - if (packageSettings.enabledComponents.contains(componentInfo.name)) { - return true; - } - if (packageSettings.disabledComponents.contains(componentInfo.name)) { - return false; - } - return componentInfo.enabled; - } - } - - // ------- apps on sdcard specific code ------- - static final boolean DEBUG_SD_INSTALL = false; - private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD"; - private static final String SD_ENCRYPTION_ALGORITHM = "AES"; - static final int MAX_CONTAINERS = 250; - private boolean mMediaMounted = false; - - private String getEncryptKey() { - try { - String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString( - SD_ENCRYPTION_KEYSTORE_NAME); - if (sdEncKey == null) { - sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128, - SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME); - if (sdEncKey == null) { - Slog.e(TAG, "Failed to create encryption keys"); - return null; - } - } - return sdEncKey; - } catch (NoSuchAlgorithmException nsae) { - Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae); - return null; - } catch (IOException ioe) { - Slog.e(TAG, "Failed to retrieve encryption keys with exception: " - + ioe); - return null; - } - - } - - /* package */ static String getTempContainerId() { - int tmpIdx = 1; - String list[] = PackageHelper.getSecureContainerList(); - if (list != null) { - for (final String name : list) { - // Ignore null and non-temporary container entries - if (name == null || !name.startsWith(mTempContainerPrefix)) { - continue; - } - - String subStr = name.substring(mTempContainerPrefix.length()); - try { - int cid = Integer.parseInt(subStr); - if (cid >= tmpIdx) { - tmpIdx = cid + 1; + if (returnCode == PackageManager.MOVE_SUCCEEDED) { + pkg.mOperationPending = true; } - } catch (NumberFormatException e) { } } - } - return mTempContainerPrefix + tmpIdx; - } - - /* - * Update media status on PackageManager. - */ - public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) { - int callingUid = Binder.getCallingUid(); - if (callingUid != 0 && callingUid != Process.SYSTEM_UID) { - throw new SecurityException("Media status can only be updated by the system"); - } - synchronized (mPackages) { - Log.i(TAG, "Updating external media status from " + - (mMediaMounted ? "mounted" : "unmounted") + " to " + - (mediaStatus ? "mounted" : "unmounted")); - if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + - mediaStatus+", mMediaMounted=" + mMediaMounted); - if (mediaStatus == mMediaMounted) { - Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, - reportStatus ? 1 : 0, -1); - mHandler.sendMessage(msg); - return; - } - mMediaMounted = mediaStatus; - } - // Queue up an async operation since the package installation may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - updateExternalMediaStatusInner(mediaStatus, reportStatus); - } - }); - } - /* - * Collect information of applications on external media, map them - * against existing containers and update information based on current - * mount status. Please note that we always have to report status - * if reportStatus has been set to true especially when unloading packages. - */ - private void updateExternalMediaStatusInner(boolean mediaStatus, - boolean reportStatus) { - // Collection of uids - int uidArr[] = null; - // Collection of stale containers - HashSet<String> removeCids = new HashSet<String>(); - // Collection of packages on external media with valid containers. - HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>(); - // Get list of secure containers. - final String list[] = PackageHelper.getSecureContainerList(); - if (list == null || list.length == 0) { - Log.i(TAG, "No secure containers on sdcard"); - } else { - // Process list of secure containers and categorize them - // as active or stale based on their package internal state. - int uidList[] = new int[list.length]; - int num = 0; - synchronized (mPackages) { - for (String cid : list) { - SdInstallArgs args = new SdInstallArgs(cid); - if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid); - String pkgName = args.getPackageName(); - if (pkgName == null) { - if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale"); - removeCids.add(cid); - continue; - } - if (DEBUG_SD_INSTALL) Log.i(TAG, "Looking for pkg : " + pkgName); - PackageSetting ps = mSettings.mPackages.get(pkgName); - // The package status is changed only if the code path - // matches between settings and the container id. - if (ps != null && ps.codePathString != null && - ps.codePathString.equals(args.getCodePath())) { - if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + - " corresponds to pkg : " + pkgName + - " at code path: " + ps.codePathString); - // We do have a valid package installed on sdcard - processCids.put(args, ps.codePathString); - int uid = ps.userId; - if (uid != -1) { - uidList[num++] = uid; - } - } else { - // Stale container on sdcard. Just delete - if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale"); - removeCids.add(cid); - } - } - } - - if (num > 0) { - // Sort uid list - Arrays.sort(uidList, 0, num); - // Throw away duplicates - uidArr = new int[num]; - uidArr[0] = uidList[0]; - int di = 0; - for (int i = 1; i < num; i++) { - if (uidList[i-1] != uidList[i]) { - uidArr[di++] = uidList[i]; - } - } - } - } - // Process packages with valid entries. - if (mediaStatus) { - if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages"); - loadMediaPackages(processCids, uidArr, removeCids); - startCleaningPackages(); - } else { - if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages"); - unloadMediaPackages(processCids, uidArr, reportStatus); - } - } - - private void sendResourcesChangedBroadcast(boolean mediaStatus, - ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) { - int size = pkgList.size(); - if (size > 0) { - // Send broadcasts here - Bundle extras = new Bundle(); - extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, - pkgList.toArray(new String[size])); - if (uidArr != null) { - extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); - } - String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE - : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; - sendPackageBroadcast(action, null, extras, null, finishedReceiver); - } - } - - /* - * Look at potentially valid container ids from processCids - * If package information doesn't match the one on record - * or package scanning fails, the cid is added to list of - * removeCids. We currently don't delete stale containers. - */ - private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, - int uidArr[], HashSet<String> removeCids) { - ArrayList<String> pkgList = new ArrayList<String>(); - Set<SdInstallArgs> keys = processCids.keySet(); - boolean doGc = false; - for (SdInstallArgs args : keys) { - String codePath = processCids.get(args); - if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading container : " - + args.cid); - int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR; - try { - // Make sure there are no container errors first. - if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) - != PackageManager.INSTALL_SUCCEEDED) { - Slog.e(TAG, "Failed to mount cid : " + args.cid + - " when installing from sdcard"); - continue; - } - // Check code path here. - if (codePath == null || !codePath.equals(args.getCodePath())) { - Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()+ - " does not match one in settings " + codePath); - continue; - } - // Parse package - int parseFlags = PackageParser.PARSE_ON_SDCARD | mDefParseFlags; - doGc = true; - synchronized (mInstallLock) { - final PackageParser.Package pkg = scanPackageLI(new File(codePath), - parseFlags, 0, 0); - // Scan the package - if (pkg != null) { - synchronized (mPackages) { - retCode = PackageManager.INSTALL_SUCCEEDED; - pkgList.add(pkg.packageName); - // Post process args - args.doPostInstall(PackageManager.INSTALL_SUCCEEDED); - } - } else { - Slog.i(TAG, "Failed to install pkg from " + - codePath + " from sdcard"); - } - } - - } finally { - if (retCode != PackageManager.INSTALL_SUCCEEDED) { - // Don't destroy container here. Wait till gc clears things up. - removeCids.add(args.cid); - } - } - } - synchronized (mPackages) { - // If the platform SDK has changed since the last time we booted, - // we need to re-grant app permission to catch any new ones that - // appear. This is really a hack, and means that apps can in some - // cases get permissions that the user didn't initially explicitly - // allow... it would be nice to have some better way to handle - // this situation. - final boolean regrantPermissions = mSettings.mExternalSdkPlatform - != mSdkVersion; - if (regrantPermissions) Slog.i(TAG, "Platform changed from " - + mSettings.mExternalSdkPlatform + " to " + mSdkVersion - + "; regranting permissions for external storage"); - mSettings.mExternalSdkPlatform = mSdkVersion; - - // Make sure group IDs have been assigned, and any permission - // changes in other apps are accounted for - updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions); - // Persist settings - mSettings.writeLP(); - } - // Send a broadcast to let everyone know we are done processing - if (pkgList.size() > 0) { - sendResourcesChangedBroadcast(true, pkgList, uidArr, null); - } - // Force gc to avoid any stale parser references that we might have. - if (doGc) { - Runtime.getRuntime().gc(); - } - // List stale containers and destroy stale temporary containers. - if (removeCids != null) { - for (String cid : removeCids) { - if (cid.startsWith(mTempContainerPrefix)) { - Log.i(TAG, "Destroying stale temporary container " + cid); - PackageHelper.destroySdDir(cid); - } else { - Log.w(TAG, "Container " + cid + " is stale"); - } - } - } - } - - /* - * Utility method to unload a list of specified containers - */ - private void unloadAllContainers(Set<SdInstallArgs> cidArgs) { - // Just unmount all valid containers. - for (SdInstallArgs arg : cidArgs) { - synchronized (mInstallLock) { - arg.doPostDeleteLI(false); - } - } - } - - /* - * Unload packages mounted on external media. This involves deleting - * package data from internal structures, sending broadcasts about - * diabled packages, gc'ing to free up references, unmounting all - * secure containers corresponding to packages on external media, and - * posting a UPDATED_MEDIA_STATUS message if status has been requested. - * Please note that we always have to post this message if status has - * been requested no matter what. - */ - private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, - int uidArr[], final boolean reportStatus) { - if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages"); - ArrayList<String> pkgList = new ArrayList<String>(); - ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>(); - final Set<SdInstallArgs> keys = processCids.keySet(); - for (SdInstallArgs args : keys) { - String cid = args.cid; - String pkgName = args.getPackageName(); - if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName); - // Delete package internally - PackageRemovedInfo outInfo = new PackageRemovedInfo(); - synchronized (mInstallLock) { - boolean res = deletePackageLI(pkgName, false, - PackageManager.DONT_DELETE_DATA, outInfo, false); - if (res) { - pkgList.add(pkgName); - } else { - Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName); - failedList.add(args); - } - } - } - - synchronized (mPackages) { - // We didn't update the settings after removing each package; - // write them now for all packages. - mSettings.writeLP(); - } - - // We have to absolutely send UPDATED_MEDIA_STATUS only - // after confirming that all the receivers processed the ordered - // broadcast when packages get disabled, force a gc to clean things up. - // and unload all the containers. - if (pkgList.size() > 0) { - sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() { - public void performReceive(Intent intent, int resultCode, String data, Bundle extras, - boolean ordered, boolean sticky) throws RemoteException { - Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, - reportStatus ? 1 : 0, 1, keys); - mHandler.sendMessage(msg); - } - }); - } else { - Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, - reportStatus ? 1 : 0, -1, keys); - mHandler.sendMessage(msg); - } - } - - public void movePackage(final String packageName, - final IPackageMoveObserver observer, final int flags) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MOVE_PACKAGE, null); - int returnCode = PackageManager.MOVE_SUCCEEDED; - int currFlags = 0; - int newFlags = 0; - synchronized (mPackages) { - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg == null) { - returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; - } else { - // Disable moving fwd locked apps and system packages - if (pkg.applicationInfo != null && isSystemApp(pkg)) { - Slog.w(TAG, "Cannot move system application"); - returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; - } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) { - Slog.w(TAG, "Cannot move forward locked app."); - returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED; - } else if (pkg.mOperationPending) { - Slog.w(TAG, "Attempt to move package which has pending operations"); - returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING; - } else { - // Find install location first - if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 && - (flags & PackageManager.MOVE_INTERNAL) != 0) { - Slog.w(TAG, "Ambigous flags specified for move location."); - returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION; - } else { - newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ? - PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL; - currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL - : PackageManager.INSTALL_INTERNAL; - if (newFlags == currFlags) { - Slog.w(TAG, "No move required. Trying to move to same location"); - returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION; - } - } - if (returnCode == PackageManager.MOVE_SUCCEEDED) { - pkg.mOperationPending = true; - } - } - } - if (returnCode != PackageManager.MOVE_SUCCEEDED) { + /* + * TODO this next block probably shouldn't be inside the lock. We + * can't guarantee these won't change after this is fired off + * anyway. + */ + if (returnCode != PackageManager.MOVE_SUCCEEDED) { processPendingMove(new MoveParams(null, observer, 0, packageName, null), returnCode); - } else { - Message msg = mHandler.obtainMessage(INIT_COPY); - InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir, + } else { + Message msg = mHandler.obtainMessage(INIT_COPY); + InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir, pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir); - MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName, + MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName, pkg.applicationInfo.dataDir); - msg.obj = mp; - mHandler.sendMessage(msg); - } - } - } + msg.obj = mp; + mHandler.sendMessage(msg); + } + } + } - private void processPendingMove(final MoveParams mp, final int currentStatus) { - // Queue up an async operation since the package deletion may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - int returnCode = currentStatus; - if (currentStatus == PackageManager.MOVE_SUCCEEDED) { - int uidArr[] = null; - ArrayList<String> pkgList = null; - synchronized (mPackages) { - PackageParser.Package pkg = mPackages.get(mp.packageName); - if (pkg == null) { - Slog.w(TAG, " Package " + mp.packageName + - " doesn't exist. Aborting move"); - returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; - } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) { - Slog.w(TAG, "Package " + mp.packageName + " code path changed from " + - mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir + - " Aborting move and returning error"); - returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR; - } else { - uidArr = new int[] { pkg.applicationInfo.uid }; - pkgList = new ArrayList<String>(); - pkgList.add(mp.packageName); - } - } - if (returnCode == PackageManager.MOVE_SUCCEEDED) { - // Send resources unavailable broadcast - sendResourcesChangedBroadcast(false, pkgList, uidArr, null); - // Update package code and resource paths - synchronized (mInstallLock) { - synchronized (mPackages) { - PackageParser.Package pkg = mPackages.get(mp.packageName); - // Recheck for package again. + private void processPendingMove(final MoveParams mp, final int currentStatus) { + // Queue up an async operation since the package deletion may take a + // little while. + mHandler.post(new Runnable() { + public void run() { + // TODO fix this; this does nothing. + mHandler.removeCallbacks(this); + int returnCode = currentStatus; + if (currentStatus == PackageManager.MOVE_SUCCEEDED) { + int uidArr[] = null; + ArrayList<String> pkgList = null; + synchronized (mPackages) { + PackageParser.Package pkg = mPackages.get(mp.packageName); + if (pkg == null) { + Slog.w(TAG, " Package " + mp.packageName + + " doesn't exist. Aborting move"); + returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; + } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) { + Slog.w(TAG, "Package " + mp.packageName + " code path changed from " + + mp.srcArgs.getCodePath() + " to " + + pkg.applicationInfo.sourceDir + + " Aborting move and returning error"); + returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR; + } else { + uidArr = new int[] { + pkg.applicationInfo.uid + }; + pkgList = new ArrayList<String>(); + pkgList.add(mp.packageName); + } + } + if (returnCode == PackageManager.MOVE_SUCCEEDED) { + // Send resources unavailable broadcast + sendResourcesChangedBroadcast(false, pkgList, uidArr, null); + // Update package code and resource paths + synchronized (mInstallLock) { + synchronized (mPackages) { + PackageParser.Package pkg = mPackages.get(mp.packageName); + // Recheck for package again. if (pkg == null) { Slog.w(TAG, " Package " + mp.packageName + " doesn't exist. Aborting move"); returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; - } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) { - Slog.w(TAG, "Package " + mp.packageName + " code path changed from " + - mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir + - " Aborting move and returning error"); - returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR; - } else { - final String oldCodePath = pkg.mPath; - final String newCodePath = mp.targetArgs.getCodePath(); - final String newResPath = mp.targetArgs.getResourcePath(); - final String newNativePath = mp.targetArgs.getNativeLibraryPath(); + } else if (!mp.srcArgs.getCodePath().equals( + pkg.applicationInfo.sourceDir)) { + Slog.w(TAG, "Package " + mp.packageName + + " code path changed from " + mp.srcArgs.getCodePath() + + " to " + pkg.applicationInfo.sourceDir + + " Aborting move and returning error"); + returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR; + } else { + final String oldCodePath = pkg.mPath; + final String newCodePath = mp.targetArgs.getCodePath(); + final String newResPath = mp.targetArgs.getResourcePath(); + final String newNativePath = mp.targetArgs + .getNativeLibraryPath(); if ((mp.flags & PackageManager.INSTALL_EXTERNAL) == 0) { if (mInstaller .unlinkNativeLibraryDirectory(pkg.applicationInfo.dataDir) < 0) { returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE; } else { - NativeLibraryHelper.copyNativeBinariesLI( - new File(newCodePath), new File(newNativePath)); + NativeLibraryHelper.copyNativeBinariesLI(new File( + newCodePath), new File(newNativePath)); } } else { if (mInstaller.linkNativeLibraryDirectory( @@ -10436,90 +7922,92 @@ class PackageManagerService extends IPackageManager.Stub { } if (returnCode == PackageManager.MOVE_SUCCEEDED) { - pkg.mScanPath = newCodePath; - pkg.applicationInfo.sourceDir = newCodePath; - pkg.applicationInfo.publicSourceDir = newResPath; - pkg.applicationInfo.nativeLibraryDir = newNativePath; - PackageSetting ps = (PackageSetting) pkg.mExtras; - ps.codePath = new File(pkg.applicationInfo.sourceDir); - ps.codePathString = ps.codePath.getPath(); - ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir); - ps.resourcePathString = ps.resourcePath.getPath(); - ps.nativeLibraryPathString = newNativePath; - // Set the application info flag correctly. - if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; - } else { - pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE; - } - ps.setFlags(pkg.applicationInfo.flags); - mAppDirs.remove(oldCodePath); - mAppDirs.put(newCodePath, pkg); - // Persist settings - mSettings.writeLP(); - } - } - } - } - // Send resources available broadcast - sendResourcesChangedBroadcast(true, pkgList, uidArr, null); - } - } - if (returnCode != PackageManager.MOVE_SUCCEEDED){ - // Clean up failed installation - if (mp.targetArgs != null) { - mp.targetArgs.doPostInstall(PackageManager.INSTALL_FAILED_INTERNAL_ERROR); - } - } else { - // Force a gc to clear things up. - Runtime.getRuntime().gc(); - // Delete older code - synchronized (mInstallLock) { - mp.srcArgs.doPostDeleteLI(true); - } - } + pkg.mScanPath = newCodePath; + pkg.applicationInfo.sourceDir = newCodePath; + pkg.applicationInfo.publicSourceDir = newResPath; + pkg.applicationInfo.nativeLibraryDir = newNativePath; + PackageSetting ps = (PackageSetting) pkg.mExtras; + ps.codePath = new File(pkg.applicationInfo.sourceDir); + ps.codePathString = ps.codePath.getPath(); + ps.resourcePath = new File( + pkg.applicationInfo.publicSourceDir); + ps.resourcePathString = ps.resourcePath.getPath(); + ps.nativeLibraryPathString = newNativePath; + // Set the application info flag + // correctly. + if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; + } else { + pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE; + } + ps.setFlags(pkg.applicationInfo.flags); + mAppDirs.remove(oldCodePath); + mAppDirs.put(newCodePath, pkg); + // Persist settings + mSettings.writeLPr(); + } + } + } + } + // Send resources available broadcast + sendResourcesChangedBroadcast(true, pkgList, uidArr, null); + } + } + if (returnCode != PackageManager.MOVE_SUCCEEDED) { + // Clean up failed installation + if (mp.targetArgs != null) { + mp.targetArgs.doPostInstall(PackageManager.INSTALL_FAILED_INTERNAL_ERROR); + } + } else { + // Force a gc to clear things up. + Runtime.getRuntime().gc(); + // Delete older code + synchronized (mInstallLock) { + mp.srcArgs.doPostDeleteLI(true); + } + } - // Allow more operations on this file if we didn't fail because - // an operation was already pending for this package. - if (returnCode != PackageManager.MOVE_FAILED_OPERATION_PENDING) { - synchronized (mPackages) { - PackageParser.Package pkg = mPackages.get(mp.packageName); - if (pkg != null) { - pkg.mOperationPending = false; + // Allow more operations on this file if we didn't fail because + // an operation was already pending for this package. + if (returnCode != PackageManager.MOVE_FAILED_OPERATION_PENDING) { + synchronized (mPackages) { + PackageParser.Package pkg = mPackages.get(mp.packageName); + if (pkg != null) { + pkg.mOperationPending = false; } } - } + } - IPackageMoveObserver observer = mp.observer; - if (observer != null) { - try { - observer.packageMoved(mp.packageName, returnCode); - } catch (RemoteException e) { - Log.i(TAG, "Observer no longer exists."); - } - } - } - }); - } + IPackageMoveObserver observer = mp.observer; + if (observer != null) { + try { + observer.packageMoved(mp.packageName, returnCode); + } catch (RemoteException e) { + Log.i(TAG, "Observer no longer exists."); + } + } + } + }); + } - public boolean setInstallLocation(int loc) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS, null); - if (getInstallLocation() == loc) { - return true; - } - if (loc == PackageHelper.APP_INSTALL_AUTO || - loc == PackageHelper.APP_INSTALL_INTERNAL || - loc == PackageHelper.APP_INSTALL_EXTERNAL) { - android.provider.Settings.System.putInt(mContext.getContentResolver(), - android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc); - return true; - } - return false; + public boolean setInstallLocation(int loc) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, + null); + if (getInstallLocation() == loc) { + return true; + } + if (loc == PackageHelper.APP_INSTALL_AUTO || loc == PackageHelper.APP_INSTALL_INTERNAL + || loc == PackageHelper.APP_INSTALL_EXTERNAL) { + android.provider.Settings.System.putInt(mContext.getContentResolver(), + android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc); + return true; + } + return false; } - public int getInstallLocation() { - return android.provider.Settings.System.getInt(mContext.getContentResolver(), - android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, PackageHelper.APP_INSTALL_AUTO); - } + public int getInstallLocation() { + return android.provider.Settings.System.getInt(mContext.getContentResolver(), + android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, + PackageHelper.APP_INSTALL_AUTO); + } } diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java new file mode 100644 index 0000000..efdc2b3 --- /dev/null +++ b/services/java/com/android/server/pm/PackageSetting.java @@ -0,0 +1,55 @@ +/* + * 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.server.pm; + +import android.content.pm.PackageParser; + +import java.io.File; + +/** + * Settings data for a particular package we know about. + */ +final class PackageSetting extends PackageSettingBase { + int userId; + PackageParser.Package pkg; + SharedUserSetting sharedUser; + + PackageSetting(String name, String realName, File codePath, File resourcePath, + String nativeLibraryPathString, int pVersionCode, int pkgFlags) { + super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode, + pkgFlags); + } + + /** + * New instance of PackageSetting replicating the original settings. + * Note that it keeps the same PackageParser.Package instance. + */ + PackageSetting(PackageSetting orig) { + super(orig); + + userId = orig.userId; + pkg = orig.pkg; + sharedUser = orig.sharedUser; + } + + @Override + public String toString() { + return "PackageSetting{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + name + "/" + userId + "}"; + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java new file mode 100644 index 0000000..e2f83ad --- /dev/null +++ b/services/java/com/android/server/pm/PackageSettingBase.java @@ -0,0 +1,207 @@ +/* + * 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.server.pm; + +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + + +import java.io.File; +import java.util.HashSet; + +/** + * Settings base class for pending and resolved classes. + */ +class PackageSettingBase extends GrantedPermissions { + /** + * Indicates the state of installation. Used by PackageManager to figure out + * incomplete installations. Say a package is being installed (the state is + * set to PKG_INSTALL_INCOMPLETE) and remains so till the package + * installation is successful or unsuccessful in which case the + * PackageManager will no longer maintain state information associated with + * the package. If some exception(like device freeze or battery being pulled + * out) occurs during installation of a package, the PackageManager needs + * this information to clean up the previously failed installation. + */ + static final int PKG_INSTALL_COMPLETE = 1; + static final int PKG_INSTALL_INCOMPLETE = 0; + + final String name; + final String realName; + File codePath; + String codePathString; + File resourcePath; + String resourcePathString; + String nativeLibraryPathString; + long timeStamp; + long firstInstallTime; + long lastUpdateTime; + int versionCode; + + boolean uidError; + + PackageSignatures signatures = new PackageSignatures(); + + boolean permissionsFixed; + boolean haveGids; + + // Whether this package is currently stopped, thus can not be + // started until explicitly launched by the user. + public boolean stopped; + + // Set to true if we have never launched this app. + public boolean notLaunched; + + /* Explicitly disabled components */ + HashSet<String> disabledComponents = new HashSet<String>(0); + /* Explicitly enabled components */ + HashSet<String> enabledComponents = new HashSet<String>(0); + int enabled = COMPONENT_ENABLED_STATE_DEFAULT; + int installStatus = PKG_INSTALL_COMPLETE; + + PackageSettingBase origPackage; + + /* package name of the app that installed this package */ + String installerPackageName; + PackageSettingBase(String name, String realName, File codePath, File resourcePath, + String nativeLibraryPathString, int pVersionCode, int pkgFlags) { + super(pkgFlags); + this.name = name; + this.realName = realName; + init(codePath, resourcePath, nativeLibraryPathString, pVersionCode); + } + + /** + * New instance of PackageSetting with one-level-deep cloning. + */ + @SuppressWarnings("unchecked") + PackageSettingBase(PackageSettingBase base) { + super(base); + + name = base.name; + realName = base.realName; + codePath = base.codePath; + codePathString = base.codePathString; + resourcePath = base.resourcePath; + resourcePathString = base.resourcePathString; + nativeLibraryPathString = base.nativeLibraryPathString; + timeStamp = base.timeStamp; + firstInstallTime = base.firstInstallTime; + lastUpdateTime = base.lastUpdateTime; + versionCode = base.versionCode; + + uidError = base.uidError; + + signatures = new PackageSignatures(base.signatures); + + permissionsFixed = base.permissionsFixed; + haveGids = base.haveGids; + stopped = base.stopped; + notLaunched = base.notLaunched; + + disabledComponents = (HashSet<String>) base.disabledComponents.clone(); + + enabledComponents = (HashSet<String>) base.enabledComponents.clone(); + + enabled = base.enabled; + installStatus = base.installStatus; + + origPackage = base.origPackage; + + installerPackageName = base.installerPackageName; + } + + void init(File codePath, File resourcePath, String nativeLibraryPathString, + int pVersionCode) { + this.codePath = codePath; + this.codePathString = codePath.toString(); + this.resourcePath = resourcePath; + this.resourcePathString = resourcePath.toString(); + this.nativeLibraryPathString = nativeLibraryPathString; + this.versionCode = pVersionCode; + } + + public void setInstallerPackageName(String packageName) { + installerPackageName = packageName; + } + + String getInstallerPackageName() { + return installerPackageName; + } + + public void setInstallStatus(int newStatus) { + installStatus = newStatus; + } + + public int getInstallStatus() { + return installStatus; + } + + public void setTimeStamp(long newStamp) { + timeStamp = newStamp; + } + + /** + * Make a shallow copy of this package settings. + */ + public void copyFrom(PackageSettingBase base) { + grantedPermissions = base.grantedPermissions; + gids = base.gids; + + timeStamp = base.timeStamp; + firstInstallTime = base.firstInstallTime; + lastUpdateTime = base.lastUpdateTime; + signatures = base.signatures; + permissionsFixed = base.permissionsFixed; + haveGids = base.haveGids; + stopped = base.stopped; + notLaunched = base.notLaunched; + disabledComponents = base.disabledComponents; + enabledComponents = base.enabledComponents; + enabled = base.enabled; + installStatus = base.installStatus; + } + + boolean enableComponentLPw(String componentClassName) { + boolean changed = disabledComponents.remove(componentClassName); + changed |= enabledComponents.add(componentClassName); + return changed; + } + + boolean disableComponentLPw(String componentClassName) { + boolean changed = enabledComponents.remove(componentClassName); + changed |= disabledComponents.add(componentClassName); + return changed; + } + + boolean restoreComponentLPw(String componentClassName) { + boolean changed = enabledComponents.remove(componentClassName); + changed |= disabledComponents.remove(componentClassName); + return changed; + } + + int getCurrentEnabledStateLPr(String componentName) { + if (enabledComponents.contains(componentName)) { + return COMPONENT_ENABLED_STATE_ENABLED; + } else if (disabledComponents.contains(componentName)) { + return COMPONENT_ENABLED_STATE_DISABLED; + } else { + return COMPONENT_ENABLED_STATE_DEFAULT; + } + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/pm/PackageSignatures.java b/services/java/com/android/server/pm/PackageSignatures.java new file mode 100644 index 0000000..a25ec6c --- /dev/null +++ b/services/java/com/android/server/pm/PackageSignatures.java @@ -0,0 +1,198 @@ +/* + * 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.server.pm; + +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import android.content.pm.Signature; +import android.util.Log; + +import java.io.IOException; +import java.util.ArrayList; + +class PackageSignatures { + Signature[] mSignatures; + + PackageSignatures(PackageSignatures orig) { + if (orig != null && orig.mSignatures != null) { + mSignatures = orig.mSignatures.clone(); + } + } + + PackageSignatures(Signature[] sigs) { + assignSignatures(sigs); + } + + PackageSignatures() { + } + + void writeXml(XmlSerializer serializer, String tagName, + ArrayList<Signature> pastSignatures) throws IOException { + if (mSignatures == null) { + return; + } + serializer.startTag(null, tagName); + serializer.attribute(null, "count", + Integer.toString(mSignatures.length)); + for (int i=0; i<mSignatures.length; i++) { + serializer.startTag(null, "cert"); + final Signature sig = mSignatures[i]; + final int sigHash = sig.hashCode(); + final int numPast = pastSignatures.size(); + int j; + for (j=0; j<numPast; j++) { + Signature pastSig = pastSignatures.get(j); + if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) { + serializer.attribute(null, "index", Integer.toString(j)); + break; + } + } + if (j >= numPast) { + pastSignatures.add(sig); + serializer.attribute(null, "index", Integer.toString(numPast)); + serializer.attribute(null, "key", sig.toCharsString()); + } + serializer.endTag(null, "cert"); + } + serializer.endTag(null, tagName); + } + + void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures) + throws IOException, XmlPullParserException { + String countStr = parser.getAttributeValue(null, "count"); + if (countStr == null) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <signatures> has" + + " no count at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + } + final int count = Integer.parseInt(countStr); + mSignatures = new Signature[count]; + int pos = 0; + + int outerDepth = parser.getDepth(); + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("cert")) { + if (pos < count) { + String index = parser.getAttributeValue(null, "index"); + if (index != null) { + try { + int idx = Integer.parseInt(index); + String key = parser.getAttributeValue(null, "key"); + if (key == null) { + if (idx >= 0 && idx < pastSignatures.size()) { + Signature sig = pastSignatures.get(idx); + if (sig != null) { + mSignatures[pos] = pastSignatures.get(idx); + pos++; + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <cert> " + + "index " + index + " is not defined at " + + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <cert> " + + "index " + index + " is out of bounds at " + + parser.getPositionDescription()); + } + } else { + while (pastSignatures.size() <= idx) { + pastSignatures.add(null); + } + Signature sig = new Signature(key); + pastSignatures.set(idx, sig); + mSignatures[pos] = sig; + pos++; + } + } catch (NumberFormatException e) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <cert> " + + "index " + index + " is not a number at " + + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <cert> has" + + " no index at " + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: too " + + "many <cert> tags, expected " + count + + " at " + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <cert>: " + + parser.getName()); + } + XmlUtils.skipCurrentTag(parser); + } + + if (pos < count) { + // Should never happen -- there is an error in the written + // settings -- but if it does we don't want to generate + // a bad array. + Signature[] newSigs = new Signature[pos]; + System.arraycopy(mSignatures, 0, newSigs, 0, pos); + mSignatures = newSigs; + } + } + + void assignSignatures(Signature[] sigs) { + if (sigs == null) { + mSignatures = null; + return; + } + mSignatures = new Signature[sigs.length]; + for (int i=0; i<sigs.length; i++) { + mSignatures[i] = sigs[i]; + } + } + + @Override + public String toString() { + StringBuffer buf = new StringBuffer(128); + buf.append("PackageSignatures{"); + buf.append(Integer.toHexString(System.identityHashCode(this))); + buf.append(" ["); + if (mSignatures != null) { + for (int i=0; i<mSignatures.length; i++) { + if (i > 0) buf.append(", "); + buf.append(Integer.toHexString( + System.identityHashCode(mSignatures[i]))); + } + } + buf.append("]}"); + return buf.toString(); + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/pm/PendingPackage.java b/services/java/com/android/server/pm/PendingPackage.java new file mode 100644 index 0000000..c17cc46 --- /dev/null +++ b/services/java/com/android/server/pm/PendingPackage.java @@ -0,0 +1,30 @@ +/* + * 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.server.pm; + +import java.io.File; + +final class PendingPackage extends PackageSettingBase { + final int sharedId; + + PendingPackage(String name, String realName, File codePath, File resourcePath, + String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) { + super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode, + pkgFlags); + this.sharedId = sharedId; + } +} diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java new file mode 100644 index 0000000..b100eb1 --- /dev/null +++ b/services/java/com/android/server/pm/PreferredActivity.java @@ -0,0 +1,73 @@ +/* + * 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.server.pm; + +import com.android.internal.util.XmlUtils; +import com.android.server.PreferredComponent; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import android.content.ComponentName; +import android.content.IntentFilter; +import android.util.Log; + +import java.io.IOException; + +class PreferredActivity extends IntentFilter implements PreferredComponent.Callbacks { + private static final String TAG = "PreferredActivity"; + + private static final boolean DEBUG_FILTERS = false; + + final PreferredComponent mPref; + + PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) { + super(filter); + mPref = new PreferredComponent(this, match, set, activity); + } + + PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException { + mPref = new PreferredComponent(this, parser); + } + + public void writeToXml(XmlSerializer serializer) throws IOException { + mPref.writeToXml(serializer); + serializer.startTag(null, "filter"); + super.writeToXml(serializer); + serializer.endTag(null, "filter"); + } + + public boolean onReadTag(String tagName, XmlPullParser parser) throws XmlPullParserException, + IOException { + if (tagName.equals("filter")) { + if (DEBUG_FILTERS) { + Log.i(TAG, "Starting to parse filter..."); + } + readFromXml(parser); + if (DEBUG_FILTERS) { + Log.i(TAG, "Finished filter: depth=" + parser.getDepth() + " tag=" + + parser.getName()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <preferred-activities>: " + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + return true; + } +} diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java new file mode 100644 index 0000000..11dde75 --- /dev/null +++ b/services/java/com/android/server/pm/Settings.java @@ -0,0 +1,2224 @@ +/* + * 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.server.pm; + +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.JournaledFile; +import com.android.internal.util.XmlUtils; +import com.android.server.IntentResolver; +import com.android.server.pm.PackageManagerService.DumpState; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PermissionInfo; +import android.content.pm.Signature; +import android.os.Binder; +import android.os.Environment; +import android.os.FileUtils; +import android.os.Process; +import android.util.Log; +import android.util.Slog; +import android.util.SparseArray; +import android.util.Xml; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +/** + * Holds information about dynamic settings. + */ +final class Settings { + private static final String TAG = "PackageSettings"; + + private static final boolean DEBUG_STOPPED = false; + + private final File mSettingsFilename; + private final File mBackupSettingsFilename; + private final File mPackageListFilename; + private final File mStoppedPackagesFilename; + private final File mBackupStoppedPackagesFilename; + final HashMap<String, PackageSetting> mPackages = + new HashMap<String, PackageSetting>(); + // List of replaced system applications + final HashMap<String, PackageSetting> mDisabledSysPackages = + new HashMap<String, PackageSetting>(); + + // These are the last platform API version we were using for + // the apps installed on internal and external storage. It is + // used to grant newer permissions one time during a system upgrade. + int mInternalSdkPlatform; + int mExternalSdkPlatform; + + // The user's preferred activities associated with particular intent + // filters. + final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities = + new IntentResolver<PreferredActivity, PreferredActivity>() { + @Override + protected String packageForFilter(PreferredActivity filter) { + return filter.mPref.mComponent.getPackageName(); + } + @Override + protected void dumpFilter(PrintWriter out, String prefix, + PreferredActivity filter) { + filter.mPref.dump(out, prefix, filter); + } + }; + final HashMap<String, SharedUserSetting> mSharedUsers = + new HashMap<String, SharedUserSetting>(); + private final ArrayList<Object> mUserIds = new ArrayList<Object>(); + private final SparseArray<Object> mOtherUserIds = + new SparseArray<Object>(); + + // For reading/writing settings file. + private final ArrayList<Signature> mPastSignatures = + new ArrayList<Signature>(); + + // Mapping from permission names to info about them. + final HashMap<String, BasePermission> mPermissions = + new HashMap<String, BasePermission>(); + + // Mapping from permission tree names to info about them. + final HashMap<String, BasePermission> mPermissionTrees = + new HashMap<String, BasePermission>(); + + // Packages that have been uninstalled and still need their external + // storage data deleted. + final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>(); + + // Packages that have been renamed since they were first installed. + // Keys are the new names of the packages, values are the original + // names. The packages appear everwhere else under their original + // names. + final HashMap<String, String> mRenamedPackages = new HashMap<String, String>(); + + final StringBuilder mReadMessages = new StringBuilder(); + + /** + * Used to track packages that have a shared user ID that hasn't been read + * in yet. + * <p> + * TODO: make this just a local variable that is passed in during package + * scanning to make it less confusing. + */ + private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>(); + + Settings() { + File dataDir = Environment.getDataDirectory(); + File systemDir = new File(dataDir, "system"); + // TODO(oam): This secure dir creation needs to be moved somewhere else (later) + File systemSecureDir = new File(dataDir, "secure/system"); + systemDir.mkdirs(); + systemSecureDir.mkdirs(); + FileUtils.setPermissions(systemDir.toString(), + FileUtils.S_IRWXU|FileUtils.S_IRWXG + |FileUtils.S_IROTH|FileUtils.S_IXOTH, + -1, -1); + FileUtils.setPermissions(systemSecureDir.toString(), + FileUtils.S_IRWXU|FileUtils.S_IRWXG + |FileUtils.S_IROTH|FileUtils.S_IXOTH, + -1, -1); + mSettingsFilename = new File(systemDir, "packages.xml"); + mBackupSettingsFilename = new File(systemDir, "packages-backup.xml"); + mPackageListFilename = new File(systemDir, "packages.list"); + mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml"); + mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml"); + } + + PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage, + String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, + String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) { + final String name = pkg.packageName; + PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath, + resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add); + return p; + } + + PackageSetting peekPackageLPr(String name) { + return mPackages.get(name); + } + + void setInstallStatus(String pkgName, int status) { + PackageSetting p = mPackages.get(pkgName); + if(p != null) { + if(p.getInstallStatus() != status) { + p.setInstallStatus(status); + } + } + } + + void setInstallerPackageName(String pkgName, + String installerPkgName) { + PackageSetting p = mPackages.get(pkgName); + if(p != null) { + p.setInstallerPackageName(installerPkgName); + } + } + + SharedUserSetting getSharedUserLPw(String name, + int pkgFlags, boolean create) { + SharedUserSetting s = mSharedUsers.get(name); + if (s == null) { + if (!create) { + return null; + } + s = new SharedUserSetting(name, pkgFlags); + if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) { + s.userId = newUserIdLPw(s); + } else { + s.userId = PackageManagerService.FIRST_APPLICATION_UID; + } + Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId); + // < 0 means we couldn't assign a userid; fall out and return + // s, which is currently null + if (s.userId >= 0) { + mSharedUsers.put(name, s); + } + } + + return s; + } + + boolean disableSystemPackageLPw(String name) { + final PackageSetting p = mPackages.get(name); + if(p == null) { + Log.w(PackageManagerService.TAG, "Package:"+name+" is not an installed package"); + return false; + } + final PackageSetting dp = mDisabledSysPackages.get(name); + // always make sure the system package code and resource paths dont change + if (dp == null) { + if((p.pkg != null) && (p.pkg.applicationInfo != null)) { + p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + mDisabledSysPackages.put(name, p); + + // a little trick... when we install the new package, we don't + // want to modify the existing PackageSetting for the built-in + // version. so at this point we need a new PackageSetting that + // is okay to muck with. + PackageSetting newp = new PackageSetting(p); + replacePackageLPw(name, newp); + return true; + } + return false; + } + + PackageSetting enableSystemPackageLPw(String name) { + PackageSetting p = mDisabledSysPackages.get(name); + if(p == null) { + Log.w(PackageManagerService.TAG, "Package:"+name+" is not disabled"); + return null; + } + // Reset flag in ApplicationInfo object + if((p.pkg != null) && (p.pkg.applicationInfo != null)) { + p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, + p.nativeLibraryPathString, p.userId, p.versionCode, p.pkgFlags); + mDisabledSysPackages.remove(name); + return ret; + } + + PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath, + String nativeLibraryPathString, int uid, int vc, int pkgFlags) { + PackageSetting p = mPackages.get(name); + if (p != null) { + if (p.userId == uid) { + return p; + } + PackageManagerService.reportSettingsProblem(Log.ERROR, + "Adding duplicate package, keeping first: " + name); + return null; + } + p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, + vc, pkgFlags); + p.userId = uid; + if (addUserIdLPw(uid, p, name)) { + mPackages.put(name, p); + return p; + } + return null; + } + + SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) { + SharedUserSetting s = mSharedUsers.get(name); + if (s != null) { + if (s.userId == uid) { + return s; + } + PackageManagerService.reportSettingsProblem(Log.ERROR, + "Adding duplicate shared user, keeping first: " + name); + return null; + } + s = new SharedUserSetting(name, pkgFlags); + s.userId = uid; + if (addUserIdLPw(uid, s, name)) { + mSharedUsers.put(name, s); + return s; + } + return null; + } + + // Transfer ownership of permissions from one package to another. + void transferPermissionsLPw(String origPkg, String newPkg) { + // Transfer ownership of permissions to the new package. + for (int i=0; i<2; i++) { + HashMap<String, BasePermission> permissions = + i == 0 ? mPermissionTrees : mPermissions; + for (BasePermission bp : permissions.values()) { + if (origPkg.equals(bp.sourcePackage)) { + if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, + "Moving permission " + bp.name + + " from pkg " + bp.sourcePackage + + " to " + newPkg); + bp.sourcePackage = newPkg; + bp.packageSetting = null; + bp.perm = null; + if (bp.pendingInfo != null) { + bp.pendingInfo.packageName = newPkg; + } + bp.uid = 0; + bp.gids = null; + } + } + } + } + + private PackageSetting getPackageLPw(String name, PackageSetting origPackage, + String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, + String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) { + PackageSetting p = mPackages.get(name); + if (p != null) { + if (!p.codePath.equals(codePath)) { + // Check to see if its a disabled system app + if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { + // This is an updated system app with versions in both system + // and data partition. Just let the most recent version + // take precedence. + Slog.w(PackageManagerService.TAG, "Trying to update system app code path from " + + p.codePathString + " to " + codePath.toString()); + } else { + // Just a change in the code path is not an issue, but + // let's log a message about it. + Slog.i(PackageManagerService.TAG, "Package " + name + " codePath changed from " + p.codePath + + " to " + codePath + "; Retaining data and using new"); + /* + * Since we've changed paths, we need to prefer the new + * native library path over the one stored in the + * package settings since we might have moved from + * internal to external storage or vice versa. + */ + p.nativeLibraryPathString = nativeLibraryPathString; + } + } + if (p.sharedUser != sharedUser) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Package " + name + " shared user changed from " + + (p.sharedUser != null ? p.sharedUser.name : "<nothing>") + + " to " + + (sharedUser != null ? sharedUser.name : "<nothing>") + + "; replacing with new"); + p = null; + } else { + if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) { + // If what we are scanning is a system package, then + // make it so, regardless of whether it was previously + // installed only in the data partition. + p.pkgFlags |= ApplicationInfo.FLAG_SYSTEM; + } + } + } + if (p == null) { + // Create a new PackageSettings entry. this can end up here because + // of code path mismatch or user id mismatch of an updated system partition + if (!create) { + return null; + } + if (origPackage != null) { + // We are consuming the data from an existing package. + p = new PackageSetting(origPackage.name, name, codePath, resourcePath, + nativeLibraryPathString, vc, pkgFlags); + if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + name + + " is adopting original package " + origPackage.name); + // Note that we will retain the new package's signature so + // that we can keep its data. + PackageSignatures s = p.signatures; + p.copyFrom(origPackage); + p.signatures = s; + p.sharedUser = origPackage.sharedUser; + p.userId = origPackage.userId; + p.origPackage = origPackage; + mRenamedPackages.put(name, origPackage.name); + name = origPackage.name; + // Update new package state. + p.setTimeStamp(codePath.lastModified()); + } else { + p = new PackageSetting(name, realName, codePath, resourcePath, + nativeLibraryPathString, vc, pkgFlags); + p.setTimeStamp(codePath.lastModified()); + p.sharedUser = sharedUser; + // If this is not a system app, it starts out stopped. + if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { + if (DEBUG_STOPPED) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(PackageManagerService.TAG, "Stopping package " + name, e); + } + p.stopped = true; + p.notLaunched = true; + } + if (sharedUser != null) { + p.userId = sharedUser.userId; + } else if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) { + // Clone the setting here for disabled system packages + PackageSetting dis = mDisabledSysPackages.get(name); + if (dis != null) { + // For disabled packages a new setting is created + // from the existing user id. This still has to be + // added to list of user id's + // Copy signatures from previous setting + if (dis.signatures.mSignatures != null) { + p.signatures.mSignatures = dis.signatures.mSignatures.clone(); + } + p.userId = dis.userId; + // Clone permissions + p.grantedPermissions = new HashSet<String>(dis.grantedPermissions); + // Clone component info + p.disabledComponents = new HashSet<String>(dis.disabledComponents); + p.enabledComponents = new HashSet<String>(dis.enabledComponents); + // Add new setting to list of user ids + addUserIdLPw(p.userId, p, name); + } else { + // Assign new user id + p.userId = newUserIdLPw(p); + } + } else { + p.userId = PackageManagerService.FIRST_APPLICATION_UID; + } + } + if (p.userId < 0) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Package " + name + " could not be assigned a valid uid"); + return null; + } + if (add) { + // Finish adding new package by adding it and updating shared + // user preferences + addPackageSettingLPw(p, name, sharedUser); + } + } + return p; + } + + void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) { + p.pkg = pkg; + pkg.mSetEnabled = p.enabled; + pkg.mSetStopped = p.stopped; + final String codePath = pkg.applicationInfo.sourceDir; + final String resourcePath = pkg.applicationInfo.publicSourceDir; + // Update code path if needed + if (!codePath.equalsIgnoreCase(p.codePathString)) { + Slog.w(PackageManagerService.TAG, "Code path for pkg : " + p.pkg.packageName + + " changing from " + p.codePathString + " to " + codePath); + p.codePath = new File(codePath); + p.codePathString = codePath; + } + //Update resource path if needed + if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) { + Slog.w(PackageManagerService.TAG, "Resource path for pkg : " + p.pkg.packageName + + " changing from " + p.resourcePathString + " to " + resourcePath); + p.resourcePath = new File(resourcePath); + p.resourcePathString = resourcePath; + } + // Update the native library path if needed + final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir; + if (nativeLibraryPath != null + && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) { + p.nativeLibraryPathString = nativeLibraryPath; + } + // Update version code if needed + if (pkg.mVersionCode != p.versionCode) { + p.versionCode = pkg.mVersionCode; + } + // Update signatures if needed. + if (p.signatures.mSignatures == null) { + p.signatures.assignSignatures(pkg.mSignatures); + } + // If this app defines a shared user id initialize + // the shared user signatures as well. + if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) { + p.sharedUser.signatures.assignSignatures(pkg.mSignatures); + } + addPackageSettingLPw(p, pkg.packageName, p.sharedUser); + } + + // Utility method that adds a PackageSetting to mPackages and + // completes updating the shared user attributes + private void addPackageSettingLPw(PackageSetting p, String name, + SharedUserSetting sharedUser) { + mPackages.put(name, p); + if (sharedUser != null) { + if (p.sharedUser != null && p.sharedUser != sharedUser) { + PackageManagerService.reportSettingsProblem(Log.ERROR, + "Package " + p.name + " was user " + + p.sharedUser + " but is now " + sharedUser + + "; I am not changing its files so it will probably fail!"); + p.sharedUser.packages.remove(p); + } else if (p.userId != sharedUser.userId) { + PackageManagerService.reportSettingsProblem(Log.ERROR, + "Package " + p.name + " was user id " + p.userId + + " but is now user " + sharedUser + + " with id " + sharedUser.userId + + "; I am not changing its files so it will probably fail!"); + } + + sharedUser.packages.add(p); + p.sharedUser = sharedUser; + p.userId = sharedUser.userId; + } + } + + /* + * Update the shared user setting when a package using + * specifying the shared user id is removed. The gids + * associated with each permission of the deleted package + * are removed from the shared user's gid list only if its + * not in use by other permissions of packages in the + * shared user setting. + */ + void updateSharedUserPermsLPw(PackageSetting deletedPs, int[] globalGids) { + if ((deletedPs == null) || (deletedPs.pkg == null)) { + Slog.i(PackageManagerService.TAG, + "Trying to update info for null package. Just ignoring"); + return; + } + // No sharedUserId + if (deletedPs.sharedUser == null) { + return; + } + SharedUserSetting sus = deletedPs.sharedUser; + // Update permissions + for (String eachPerm : deletedPs.pkg.requestedPermissions) { + boolean used = false; + if (!sus.grantedPermissions.contains(eachPerm)) { + continue; + } + for (PackageSetting pkg:sus.packages) { + if (pkg.pkg != null && + !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) && + pkg.pkg.requestedPermissions.contains(eachPerm)) { + used = true; + break; + } + } + if (!used) { + // can safely delete this permission from list + sus.grantedPermissions.remove(eachPerm); + } + } + // Update gids + int newGids[] = globalGids; + for (String eachPerm : sus.grantedPermissions) { + BasePermission bp = mPermissions.get(eachPerm); + if (bp != null) { + newGids = PackageManagerService.appendInts(newGids, bp.gids); + } + } + sus.gids = newGids; + } + + int removePackageLPw(String name) { + final PackageSetting p = mPackages.get(name); + if (p != null) { + mPackages.remove(name); + if (p.sharedUser != null) { + p.sharedUser.packages.remove(p); + if (p.sharedUser.packages.size() == 0) { + mSharedUsers.remove(p.sharedUser.name); + removeUserIdLPw(p.sharedUser.userId); + return p.sharedUser.userId; + } + } else { + removeUserIdLPw(p.userId); + return p.userId; + } + } + return -1; + } + + private void replacePackageLPw(String name, PackageSetting newp) { + final PackageSetting p = mPackages.get(name); + if (p != null) { + if (p.sharedUser != null) { + p.sharedUser.packages.remove(p); + p.sharedUser.packages.add(newp); + } else { + replaceUserIdLPw(p.userId, newp); + } + } + mPackages.put(name, newp); + } + + private boolean addUserIdLPw(int uid, Object obj, Object name) { + if (uid >= PackageManagerService.FIRST_APPLICATION_UID + PackageManagerService.MAX_APPLICATION_UIDS) { + return false; + } + + if (uid >= PackageManagerService.FIRST_APPLICATION_UID) { + int N = mUserIds.size(); + final int index = uid - PackageManagerService.FIRST_APPLICATION_UID; + while (index >= N) { + mUserIds.add(null); + N++; + } + if (mUserIds.get(index) != null) { + PackageManagerService.reportSettingsProblem(Log.ERROR, + "Adding duplicate user id: " + uid + + " name=" + name); + return false; + } + mUserIds.set(index, obj); + } else { + if (mOtherUserIds.get(uid) != null) { + PackageManagerService.reportSettingsProblem(Log.ERROR, + "Adding duplicate shared id: " + uid + + " name=" + name); + return false; + } + mOtherUserIds.put(uid, obj); + } + return true; + } + + public Object getUserIdLPr(int uid) { + if (uid >= PackageManagerService.FIRST_APPLICATION_UID) { + final int N = mUserIds.size(); + final int index = uid - PackageManagerService.FIRST_APPLICATION_UID; + return index < N ? mUserIds.get(index) : null; + } else { + return mOtherUserIds.get(uid); + } + } + + private void removeUserIdLPw(int uid) { + if (uid >= PackageManagerService.FIRST_APPLICATION_UID) { + final int N = mUserIds.size(); + final int index = uid - PackageManagerService.FIRST_APPLICATION_UID; + if (index < N) mUserIds.set(index, null); + } else { + mOtherUserIds.remove(uid); + } + } + + private void replaceUserIdLPw(int uid, Object obj) { + if (uid >= PackageManagerService.FIRST_APPLICATION_UID) { + final int N = mUserIds.size(); + final int index = uid - PackageManagerService.FIRST_APPLICATION_UID; + if (index < N) mUserIds.set(index, obj); + } else { + mOtherUserIds.put(uid, obj); + } + } + + void writeStoppedLPr() { + // Keep the old stopped packages around until we know the new ones have + // been successfully written. + if (mStoppedPackagesFilename.exists()) { + // Presence of backup settings file indicates that we failed + // to persist packages earlier. So preserve the older + // backup for future reference since the current packages + // might have been corrupted. + if (!mBackupStoppedPackagesFilename.exists()) { + if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) { + Log.wtf(PackageManagerService.TAG, "Unable to backup package manager stopped packages, " + + "current changes will be lost at reboot"); + return; + } + } else { + mStoppedPackagesFilename.delete(); + Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup"); + } + } + + try { + final FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename); + final BufferedOutputStream str = new BufferedOutputStream(fstr); + + //XmlSerializer serializer = XmlUtils.serializerInstance(); + final XmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(str, "utf-8"); + serializer.startDocument(null, true); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + + serializer.startTag(null, "stopped-packages"); + + for (final PackageSetting pkg : mPackages.values()) { + if (pkg.stopped) { + serializer.startTag(null, "pkg"); + serializer.attribute(null, "name", pkg.name); + if (pkg.notLaunched) { + serializer.attribute(null, "nl", "1"); + } + serializer.endTag(null, "pkg"); + } + } + + serializer.endTag(null, "stopped-packages"); + + serializer.endDocument(); + + str.flush(); + FileUtils.sync(fstr); + str.close(); + + // New settings successfully written, old ones are no longer + // needed. + mBackupStoppedPackagesFilename.delete(); + FileUtils.setPermissions(mStoppedPackagesFilename.toString(), + FileUtils.S_IRUSR|FileUtils.S_IWUSR + |FileUtils.S_IRGRP|FileUtils.S_IWGRP + |FileUtils.S_IROTH, + -1, -1); + + // Done, all is good! + return; + } catch(java.io.IOException e) { + Log.wtf(PackageManagerService.TAG, "Unable to write package manager stopped packages, " + + " current changes will be lost at reboot", e); + } + + // Clean up partially written files + if (mStoppedPackagesFilename.exists()) { + if (!mStoppedPackagesFilename.delete()) { + Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename); + } + } + } + + // Note: assumed "stopped" field is already cleared in all packages. + void readStoppedLPw() { + FileInputStream str = null; + if (mBackupStoppedPackagesFilename.exists()) { + try { + str = new FileInputStream(mBackupStoppedPackagesFilename); + mReadMessages.append("Reading from backup stopped packages file\n"); + PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file"); + if (mSettingsFilename.exists()) { + // If both the backup and normal file exist, we + // ignore the normal one since it might have been + // corrupted. + Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file " + + mStoppedPackagesFilename); + mStoppedPackagesFilename.delete(); + } + } catch (java.io.IOException e) { + // We'll try for the normal settings file. + } + } + + try { + if (str == null) { + if (!mStoppedPackagesFilename.exists()) { + mReadMessages.append("No stopped packages file found\n"); + PackageManagerService.reportSettingsProblem(Log.INFO, "No stopped packages file file; " + + "assuming all started"); + // At first boot, make sure no packages are stopped. + // We usually want to have third party apps initialize + // in the stopped state, but not at first boot. + for (PackageSetting pkg : mPackages.values()) { + pkg.stopped = false; + pkg.notLaunched = false; + } + return; + } + str = new FileInputStream(mStoppedPackagesFilename); + } + final XmlPullParser parser = Xml.newPullParser(); + parser.setInput(str, null); + + int type; + while ((type=parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + ; + } + + if (type != XmlPullParser.START_TAG) { + mReadMessages.append("No start tag found in stopped packages file\n"); + PackageManagerService.reportSettingsProblem(Log.WARN, + "No start tag found in package manager stopped packages"); + return; + } + + int outerDepth = parser.getDepth(); + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("pkg")) { + String name = parser.getAttributeValue(null, "name"); + PackageSetting ps = mPackages.get(name); + if (ps != null) { + ps.stopped = true; + if ("1".equals(parser.getAttributeValue(null, "nl"))) { + ps.notLaunched = true; + } + } else { + Slog.w(PackageManagerService.TAG, "No package known for stopped package: " + name); + } + XmlUtils.skipCurrentTag(parser); + } else { + Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: " + + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + + str.close(); + + } catch(XmlPullParserException e) { + mReadMessages.append("Error reading: " + e.toString()); + PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e); + Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e); + + } catch(java.io.IOException e) { + mReadMessages.append("Error reading: " + e.toString()); + PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); + Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e); + + } + } + + void writeLPr() { + //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024); + + // Keep the old settings around until we know the new ones have + // been successfully written. + if (mSettingsFilename.exists()) { + // Presence of backup settings file indicates that we failed + // to persist settings earlier. So preserve the older + // backup for future reference since the current settings + // might have been corrupted. + if (!mBackupSettingsFilename.exists()) { + if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) { + Log.wtf(PackageManagerService.TAG, "Unable to backup package manager settings, " + + " current changes will be lost at reboot"); + return; + } + } else { + mSettingsFilename.delete(); + Slog.w(PackageManagerService.TAG, "Preserving older settings backup"); + } + } + + mPastSignatures.clear(); + + try { + FileOutputStream fstr = new FileOutputStream(mSettingsFilename); + BufferedOutputStream str = new BufferedOutputStream(fstr); + + //XmlSerializer serializer = XmlUtils.serializerInstance(); + XmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(str, "utf-8"); + serializer.startDocument(null, true); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + + serializer.startTag(null, "packages"); + + serializer.startTag(null, "last-platform-version"); + serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform)); + serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform)); + serializer.endTag(null, "last-platform-version"); + + serializer.startTag(null, "permission-trees"); + for (BasePermission bp : mPermissionTrees.values()) { + writePermissionLPr(serializer, bp); + } + serializer.endTag(null, "permission-trees"); + + serializer.startTag(null, "permissions"); + for (BasePermission bp : mPermissions.values()) { + writePermissionLPr(serializer, bp); + } + serializer.endTag(null, "permissions"); + + for (final PackageSetting pkg : mPackages.values()) { + writePackageLPr(serializer, pkg); + } + + for (final PackageSetting pkg : mDisabledSysPackages.values()) { + writeDisabledSysPackageLPr(serializer, pkg); + } + + serializer.startTag(null, "preferred-activities"); + for (final PreferredActivity pa : mPreferredActivities.filterSet()) { + serializer.startTag(null, "item"); + pa.writeToXml(serializer); + serializer.endTag(null, "item"); + } + serializer.endTag(null, "preferred-activities"); + + for (final SharedUserSetting usr : mSharedUsers.values()) { + serializer.startTag(null, "shared-user"); + serializer.attribute(null, "name", usr.name); + serializer.attribute(null, "userId", + Integer.toString(usr.userId)); + usr.signatures.writeXml(serializer, "sigs", mPastSignatures); + serializer.startTag(null, "perms"); + for (String name : usr.grantedPermissions) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + serializer.endTag(null, "perms"); + serializer.endTag(null, "shared-user"); + } + + if (mPackagesToBeCleaned.size() > 0) { + for (int i=0; i<mPackagesToBeCleaned.size(); i++) { + serializer.startTag(null, "cleaning-package"); + serializer.attribute(null, "name", mPackagesToBeCleaned.get(i)); + serializer.endTag(null, "cleaning-package"); + } + } + + if (mRenamedPackages.size() > 0) { + for (HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) { + serializer.startTag(null, "renamed-package"); + serializer.attribute(null, "new", e.getKey()); + serializer.attribute(null, "old", e.getValue()); + serializer.endTag(null, "renamed-package"); + } + } + + serializer.endTag(null, "packages"); + + serializer.endDocument(); + + str.flush(); + FileUtils.sync(fstr); + str.close(); + + // New settings successfully written, old ones are no longer + // needed. + mBackupSettingsFilename.delete(); + FileUtils.setPermissions(mSettingsFilename.toString(), + FileUtils.S_IRUSR|FileUtils.S_IWUSR + |FileUtils.S_IRGRP|FileUtils.S_IWGRP + |FileUtils.S_IROTH, + -1, -1); + + // Write package list file now, use a JournaledFile. + // + File tempFile = new File(mPackageListFilename.toString() + ".tmp"); + JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile); + + fstr = new FileOutputStream(journal.chooseForWrite()); + str = new BufferedOutputStream(fstr); + try { + StringBuilder sb = new StringBuilder(); + for (final PackageSetting pkg : mPackages.values()) { + ApplicationInfo ai = pkg.pkg.applicationInfo; + String dataPath = ai.dataDir; + boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + + // Avoid any application that has a space in its path + // or that is handled by the system. + if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID) + continue; + + // we store on each line the following information for now: + // + // pkgName - package name + // userId - application-specific user id + // debugFlag - 0 or 1 if the package is debuggable. + // dataPath - path to package's data path + // + // NOTE: We prefer not to expose all ApplicationInfo flags for now. + // + // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS + // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES: + // system/core/run-as/run-as.c + // + sb.setLength(0); + sb.append(ai.packageName); + sb.append(" "); + sb.append((int)ai.uid); + sb.append(isDebug ? " 1 " : " 0 "); + sb.append(dataPath); + sb.append("\n"); + str.write(sb.toString().getBytes()); + } + str.flush(); + FileUtils.sync(fstr); + str.close(); + journal.commit(); + } + catch (Exception e) { + journal.rollback(); + } + + FileUtils.setPermissions(mPackageListFilename.toString(), + FileUtils.S_IRUSR|FileUtils.S_IWUSR + |FileUtils.S_IRGRP|FileUtils.S_IWGRP + |FileUtils.S_IROTH, + -1, -1); + + writeStoppedLPr(); + + return; + + } catch(XmlPullParserException e) { + Log.wtf(PackageManagerService.TAG, "Unable to write package manager settings, " + + "current changes will be lost at reboot", e); + } catch(java.io.IOException e) { + Log.wtf(PackageManagerService.TAG, "Unable to write package manager settings, " + + "current changes will be lost at reboot", e); + } + // Clean up partially written files + if (mSettingsFilename.exists()) { + if (!mSettingsFilename.delete()) { + Log.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: " + mSettingsFilename); + } + } + //Debug.stopMethodTracing(); + } + + void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg) + throws java.io.IOException { + serializer.startTag(null, "updated-package"); + serializer.attribute(null, "name", pkg.name); + if (pkg.realName != null) { + serializer.attribute(null, "realName", pkg.realName); + } + serializer.attribute(null, "codePath", pkg.codePathString); + serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp)); + serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime)); + serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime)); + serializer.attribute(null, "version", String.valueOf(pkg.versionCode)); + if (!pkg.resourcePathString.equals(pkg.codePathString)) { + serializer.attribute(null, "resourcePath", pkg.resourcePathString); + } + if (pkg.nativeLibraryPathString != null) { + serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); + } + if (pkg.sharedUser == null) { + serializer.attribute(null, "userId", Integer.toString(pkg.userId)); + } else { + serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId)); + } + serializer.startTag(null, "perms"); + if (pkg.sharedUser == null) { + // If this is a shared user, the permissions will + // be written there. We still need to write an + // empty permissions list so permissionsFixed will + // be set. + for (final String name : pkg.grantedPermissions) { + BasePermission bp = mPermissions.get(name); + if (bp != null) { + // We only need to write signature or system permissions but + // this wont + // match the semantics of grantedPermissions. So write all + // permissions. + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + } + } + serializer.endTag(null, "perms"); + serializer.endTag(null, "updated-package"); + } + + void writePackageLPr(XmlSerializer serializer, final PackageSetting pkg) + throws java.io.IOException { + serializer.startTag(null, "package"); + serializer.attribute(null, "name", pkg.name); + if (pkg.realName != null) { + serializer.attribute(null, "realName", pkg.realName); + } + serializer.attribute(null, "codePath", pkg.codePathString); + if (!pkg.resourcePathString.equals(pkg.codePathString)) { + serializer.attribute(null, "resourcePath", pkg.resourcePathString); + } + if (pkg.nativeLibraryPathString != null) { + serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); + } + serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags)); + serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp)); + serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime)); + serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime)); + serializer.attribute(null, "version", String.valueOf(pkg.versionCode)); + if (pkg.sharedUser == null) { + serializer.attribute(null, "userId", Integer.toString(pkg.userId)); + } else { + serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId)); + } + if (pkg.uidError) { + serializer.attribute(null, "uidError", "true"); + } + if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { + serializer.attribute(null, "enabled", + pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED ? "true" : "false"); + } + if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) { + serializer.attribute(null, "installStatus", "false"); + } + if (pkg.installerPackageName != null) { + serializer.attribute(null, "installer", pkg.installerPackageName); + } + pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); + if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { + serializer.startTag(null, "perms"); + if (pkg.sharedUser == null) { + // If this is a shared user, the permissions will + // be written there. We still need to write an + // empty permissions list so permissionsFixed will + // be set. + for (final String name : pkg.grantedPermissions) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + } + serializer.endTag(null, "perms"); + } + if (pkg.disabledComponents.size() > 0) { + serializer.startTag(null, "disabled-components"); + for (final String name : pkg.disabledComponents) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + serializer.endTag(null, "disabled-components"); + } + if (pkg.enabledComponents.size() > 0) { + serializer.startTag(null, "enabled-components"); + for (final String name : pkg.enabledComponents) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + serializer.endTag(null, "enabled-components"); + } + + serializer.endTag(null, "package"); + } + + void writePermissionLPr(XmlSerializer serializer, BasePermission bp) + throws XmlPullParserException, java.io.IOException { + if (bp.type != BasePermission.TYPE_BUILTIN && bp.sourcePackage != null) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", bp.name); + serializer.attribute(null, "package", bp.sourcePackage); + if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) { + serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel)); + } + if (PackageManagerService.DEBUG_SETTINGS) + Log.v(PackageManagerService.TAG, "Writing perm: name=" + bp.name + " type=" + + bp.type); + if (bp.type == BasePermission.TYPE_DYNAMIC) { + final PermissionInfo pi = bp.perm != null ? bp.perm.info : bp.pendingInfo; + if (pi != null) { + serializer.attribute(null, "type", "dynamic"); + if (pi.icon != 0) { + serializer.attribute(null, "icon", Integer.toString(pi.icon)); + } + if (pi.nonLocalizedLabel != null) { + serializer.attribute(null, "label", pi.nonLocalizedLabel.toString()); + } + } + } + serializer.endTag(null, "item"); + } + } + + ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() { + final HashSet<String> kList = new HashSet<String>(mPackages.keySet()); + final Iterator<String> its = kList.iterator(); + final ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>(); + while (its.hasNext()) { + final String key = its.next(); + final PackageSetting ps = mPackages.get(key); + if (ps.getInstallStatus() == PackageSettingBase.PKG_INSTALL_INCOMPLETE) { + ret.add(ps); + } + } + return ret; + } + + boolean readLPw() { + FileInputStream str = null; + if (mBackupSettingsFilename.exists()) { + try { + str = new FileInputStream(mBackupSettingsFilename); + mReadMessages.append("Reading from backup settings file\n"); + PackageManagerService.reportSettingsProblem(Log.INFO, + "Need to read from backup settings file"); + if (mSettingsFilename.exists()) { + // If both the backup and settings file exist, we + // ignore the settings since it might have been + // corrupted. + Slog.w(PackageManagerService.TAG, "Cleaning up settings file " + + mSettingsFilename); + mSettingsFilename.delete(); + } + } catch (java.io.IOException e) { + // We'll try for the normal settings file. + } + } + + mPendingPackages.clear(); + mPastSignatures.clear(); + + try { + if (str == null) { + if (!mSettingsFilename.exists()) { + mReadMessages.append("No settings file found\n"); + PackageManagerService.reportSettingsProblem(Log.INFO, + "No settings file; creating initial state"); + return false; + } + str = new FileInputStream(mSettingsFilename); + } + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(str, null); + + int type; + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + ; + } + + if (type != XmlPullParser.START_TAG) { + mReadMessages.append("No start tag found in settings file\n"); + PackageManagerService.reportSettingsProblem(Log.WARN, + "No start tag found in package manager settings"); + Log + .wtf(PackageManagerService.TAG, + "No start tag found in package manager settings"); + return false; + } + + int outerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("package")) { + readPackageLPw(parser); + } else if (tagName.equals("permissions")) { + readPermissionsLPw(mPermissions, parser); + } else if (tagName.equals("permission-trees")) { + readPermissionsLPw(mPermissionTrees, parser); + } else if (tagName.equals("shared-user")) { + readSharedUserLPw(parser); + } else if (tagName.equals("preferred-packages")) { + // no longer used. + } else if (tagName.equals("preferred-activities")) { + readPreferredActivitiesLPw(parser); + } else if (tagName.equals("updated-package")) { + readDisabledSysPackageLPw(parser); + } else if (tagName.equals("cleaning-package")) { + String name = parser.getAttributeValue(null, "name"); + if (name != null) { + mPackagesToBeCleaned.add(name); + } + } else if (tagName.equals("renamed-package")) { + String nname = parser.getAttributeValue(null, "new"); + String oname = parser.getAttributeValue(null, "old"); + if (nname != null && oname != null) { + mRenamedPackages.put(nname, oname); + } + } else if (tagName.equals("last-platform-version")) { + mInternalSdkPlatform = mExternalSdkPlatform = 0; + try { + String internal = parser.getAttributeValue(null, "internal"); + if (internal != null) { + mInternalSdkPlatform = Integer.parseInt(internal); + } + String external = parser.getAttributeValue(null, "external"); + if (external != null) { + mExternalSdkPlatform = Integer.parseInt(external); + } + } catch (NumberFormatException e) { + } + } else { + Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: " + + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + + str.close(); + + } catch (XmlPullParserException e) { + mReadMessages.append("Error reading: " + e.toString()); + PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); + Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e); + + } catch (java.io.IOException e) { + mReadMessages.append("Error reading: " + e.toString()); + PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); + Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e); + + } + + final int N = mPendingPackages.size(); + for (int i = 0; i < N; i++) { + final PendingPackage pp = mPendingPackages.get(i); + Object idObj = getUserIdLPr(pp.sharedId); + if (idObj != null && idObj instanceof SharedUserSetting) { + PackageSetting p = getPackageLPw(pp.name, null, pp.realName, + (SharedUserSetting) idObj, pp.codePath, pp.resourcePath, + pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true); + if (p == null) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unable to create application package for " + pp.name); + continue; + } + p.copyFrom(pp); + } else if (idObj != null) { + String msg = "Bad package setting: package " + pp.name + " has shared uid " + + pp.sharedId + " that is not a shared uid\n"; + mReadMessages.append(msg); + PackageManagerService.reportSettingsProblem(Log.ERROR, msg); + } else { + String msg = "Bad package setting: package " + pp.name + " has shared uid " + + pp.sharedId + " that is not defined\n"; + mReadMessages.append(msg); + PackageManagerService.reportSettingsProblem(Log.ERROR, msg); + } + } + mPendingPackages.clear(); + + readStoppedLPw(); + + mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, " + + mSharedUsers.size() + " shared uids\n"); + + return true; + } + + private int readInt(XmlPullParser parser, String ns, String name, int defValue) { + String v = parser.getAttributeValue(ns, name); + try { + if (v == null) { + return defValue; + } + return Integer.parseInt(v); + } catch (NumberFormatException e) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: attribute " + name + + " has bad integer value " + v + " at " + + parser.getPositionDescription()); + } + return defValue; + } + + private void readPermissionsLPw(HashMap<String, BasePermission> out, XmlPullParser parser) + throws IOException, XmlPullParserException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final String tagName = parser.getName(); + if (tagName.equals("item")) { + final String name = parser.getAttributeValue(null, "name"); + final String sourcePackage = parser.getAttributeValue(null, "package"); + final String ptype = parser.getAttributeValue(null, "type"); + if (name != null && sourcePackage != null) { + final boolean dynamic = "dynamic".equals(ptype); + final BasePermission bp = new BasePermission(name, sourcePackage, + dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL); + bp.protectionLevel = readInt(parser, null, "protection", + PermissionInfo.PROTECTION_NORMAL); + if (dynamic) { + PermissionInfo pi = new PermissionInfo(); + pi.packageName = sourcePackage.intern(); + pi.name = name.intern(); + pi.icon = readInt(parser, null, "icon", 0); + pi.nonLocalizedLabel = parser.getAttributeValue(null, "label"); + pi.protectionLevel = bp.protectionLevel; + bp.pendingInfo = pi; + } + out.put(bp.name, bp); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: permissions has" + " no name at " + + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element reading permissions: " + parser.getName() + " at " + + parser.getPositionDescription()); + } + XmlUtils.skipCurrentTag(parser); + } + } + + private void readDisabledSysPackageLPw(XmlPullParser parser) throws XmlPullParserException, + IOException { + String name = parser.getAttributeValue(null, "name"); + String realName = parser.getAttributeValue(null, "realName"); + String codePathStr = parser.getAttributeValue(null, "codePath"); + String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); + String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); + if (resourcePathStr == null) { + resourcePathStr = codePathStr; + } + String version = parser.getAttributeValue(null, "version"); + int versionCode = 0; + if (version != null) { + try { + versionCode = Integer.parseInt(version); + } catch (NumberFormatException e) { + } + } + + int pkgFlags = 0; + pkgFlags |= ApplicationInfo.FLAG_SYSTEM; + PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr), + new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags); + String timeStampStr = parser.getAttributeValue(null, "ft"); + if (timeStampStr != null) { + try { + long timeStamp = Long.parseLong(timeStampStr, 16); + ps.setTimeStamp(timeStamp); + } catch (NumberFormatException e) { + } + } else { + timeStampStr = parser.getAttributeValue(null, "ts"); + if (timeStampStr != null) { + try { + long timeStamp = Long.parseLong(timeStampStr); + ps.setTimeStamp(timeStamp); + } catch (NumberFormatException e) { + } + } + } + timeStampStr = parser.getAttributeValue(null, "it"); + if (timeStampStr != null) { + try { + ps.firstInstallTime = Long.parseLong(timeStampStr, 16); + } catch (NumberFormatException e) { + } + } + timeStampStr = parser.getAttributeValue(null, "ut"); + if (timeStampStr != null) { + try { + ps.lastUpdateTime = Long.parseLong(timeStampStr, 16); + } catch (NumberFormatException e) { + } + } + String idStr = parser.getAttributeValue(null, "userId"); + ps.userId = idStr != null ? Integer.parseInt(idStr) : 0; + if (ps.userId <= 0) { + String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); + ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; + } + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("perms")) { + readGrantedPermissionsLPw(parser, ps.grantedPermissions); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <updated-package>: " + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + mDisabledSysPackages.put(name, ps); + } + + private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException { + String name = null; + String realName = null; + String idStr = null; + String sharedIdStr = null; + String codePathStr = null; + String resourcePathStr = null; + String nativeLibraryPathStr = null; + String systemStr = null; + String installerPackageName = null; + String uidError = null; + int pkgFlags = 0; + long timeStamp = 0; + long firstInstallTime = 0; + long lastUpdateTime = 0; + PackageSettingBase packageSetting = null; + String version = null; + int versionCode = 0; + try { + name = parser.getAttributeValue(null, "name"); + realName = parser.getAttributeValue(null, "realName"); + idStr = parser.getAttributeValue(null, "userId"); + uidError = parser.getAttributeValue(null, "uidError"); + sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); + codePathStr = parser.getAttributeValue(null, "codePath"); + resourcePathStr = parser.getAttributeValue(null, "resourcePath"); + nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); + version = parser.getAttributeValue(null, "version"); + if (version != null) { + try { + versionCode = Integer.parseInt(version); + } catch (NumberFormatException e) { + } + } + installerPackageName = parser.getAttributeValue(null, "installer"); + + systemStr = parser.getAttributeValue(null, "flags"); + if (systemStr != null) { + try { + pkgFlags = Integer.parseInt(systemStr); + } catch (NumberFormatException e) { + } + } else { + // For backward compatibility + systemStr = parser.getAttributeValue(null, "system"); + if (systemStr != null) { + pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM + : 0; + } else { + // Old settings that don't specify system... just treat + // them as system, good enough. + pkgFlags |= ApplicationInfo.FLAG_SYSTEM; + } + } + String timeStampStr = parser.getAttributeValue(null, "ft"); + if (timeStampStr != null) { + try { + timeStamp = Long.parseLong(timeStampStr, 16); + } catch (NumberFormatException e) { + } + } else { + timeStampStr = parser.getAttributeValue(null, "ts"); + if (timeStampStr != null) { + try { + timeStamp = Long.parseLong(timeStampStr); + } catch (NumberFormatException e) { + } + } + } + timeStampStr = parser.getAttributeValue(null, "it"); + if (timeStampStr != null) { + try { + firstInstallTime = Long.parseLong(timeStampStr, 16); + } catch (NumberFormatException e) { + } + } + timeStampStr = parser.getAttributeValue(null, "ut"); + if (timeStampStr != null) { + try { + lastUpdateTime = Long.parseLong(timeStampStr, 16); + } catch (NumberFormatException e) { + } + } + if (PackageManagerService.DEBUG_SETTINGS) + Log.v(PackageManagerService.TAG, "Reading package: " + name + " userId=" + idStr + + " sharedUserId=" + sharedIdStr); + int userId = idStr != null ? Integer.parseInt(idStr) : 0; + if (resourcePathStr == null) { + resourcePathStr = codePathStr; + } + if (realName != null) { + realName = realName.intern(); + } + if (name == null) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <package> has no name at " + + parser.getPositionDescription()); + } else if (codePathStr == null) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <package> has no codePath at " + + parser.getPositionDescription()); + } else if (userId > 0) { + packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr), + new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode, + pkgFlags); + if (PackageManagerService.DEBUG_SETTINGS) + Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId=" + + userId + " pkg=" + packageSetting); + if (packageSetting == null) { + PackageManagerService.reportSettingsProblem(Log.ERROR, "Failure adding uid " + + userId + " while parsing settings at " + + parser.getPositionDescription()); + } else { + packageSetting.setTimeStamp(timeStamp); + packageSetting.firstInstallTime = firstInstallTime; + packageSetting.lastUpdateTime = lastUpdateTime; + } + } else if (sharedIdStr != null) { + userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; + if (userId > 0) { + packageSetting = new PendingPackage(name.intern(), realName, new File( + codePathStr), new File(resourcePathStr), nativeLibraryPathStr, userId, + versionCode, pkgFlags); + packageSetting.setTimeStamp(timeStamp); + packageSetting.firstInstallTime = firstInstallTime; + packageSetting.lastUpdateTime = lastUpdateTime; + mPendingPackages.add((PendingPackage) packageSetting); + if (PackageManagerService.DEBUG_SETTINGS) + Log.i(PackageManagerService.TAG, "Reading package " + name + + ": sharedUserId=" + userId + " pkg=" + packageSetting); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: package " + name + + " has bad sharedId " + sharedIdStr + " at " + + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: package " + name + " has bad userId " + + idStr + " at " + parser.getPositionDescription()); + } + } catch (NumberFormatException e) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: package " + name + " has bad userId " + + idStr + " at " + parser.getPositionDescription()); + } + if (packageSetting != null) { + packageSetting.uidError = "true".equals(uidError); + packageSetting.installerPackageName = installerPackageName; + packageSetting.nativeLibraryPathString = nativeLibraryPathStr; + final String enabledStr = parser.getAttributeValue(null, "enabled"); + if (enabledStr != null) { + if (enabledStr.equalsIgnoreCase("true")) { + packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED; + } else if (enabledStr.equalsIgnoreCase("false")) { + packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED; + } else if (enabledStr.equalsIgnoreCase("default")) { + packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: package " + name + + " has bad enabled value: " + idStr + " at " + + parser.getPositionDescription()); + } + } else { + packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; + } + final String installStatusStr = parser.getAttributeValue(null, "installStatus"); + if (installStatusStr != null) { + if (installStatusStr.equalsIgnoreCase("false")) { + packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_INCOMPLETE; + } else { + packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_COMPLETE; + } + } + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("disabled-components")) { + readDisabledComponentsLPw(packageSetting, parser); + } else if (tagName.equals("enabled-components")) { + readEnabledComponentsLPw(packageSetting, parser); + } else if (tagName.equals("sigs")) { + packageSetting.signatures.readXml(parser, mPastSignatures); + } else if (tagName.equals("perms")) { + readGrantedPermissionsLPw(parser, packageSetting.grantedPermissions); + packageSetting.permissionsFixed = true; + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <package>: " + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + } else { + XmlUtils.skipCurrentTag(parser); + } + } + + private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser) + throws IOException, XmlPullParserException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("item")) { + String name = parser.getAttributeValue(null, "name"); + if (name != null) { + packageSetting.disabledComponents.add(name.intern()); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <disabled-components> has" + + " no name at " + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <disabled-components>: " + parser.getName()); + } + XmlUtils.skipCurrentTag(parser); + } + } + + private void readEnabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser) + throws IOException, XmlPullParserException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("item")) { + String name = parser.getAttributeValue(null, "name"); + if (name != null) { + packageSetting.enabledComponents.add(name.intern()); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <enabled-components> has" + + " no name at " + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <enabled-components>: " + parser.getName()); + } + XmlUtils.skipCurrentTag(parser); + } + } + + private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException, IOException { + String name = null; + String idStr = null; + int pkgFlags = 0; + SharedUserSetting su = null; + try { + name = parser.getAttributeValue(null, "name"); + idStr = parser.getAttributeValue(null, "userId"); + int userId = idStr != null ? Integer.parseInt(idStr) : 0; + if ("true".equals(parser.getAttributeValue(null, "system"))) { + pkgFlags |= ApplicationInfo.FLAG_SYSTEM; + } + if (name == null) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <shared-user> has no name at " + + parser.getPositionDescription()); + } else if (userId == 0) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: shared-user " + name + + " has bad userId " + idStr + " at " + + parser.getPositionDescription()); + } else { + if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) { + PackageManagerService + .reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at " + + parser.getPositionDescription()); + } + } + } catch (NumberFormatException e) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: package " + name + " has bad userId " + + idStr + " at " + parser.getPositionDescription()); + } + ; + + if (su != null) { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("sigs")) { + su.signatures.readXml(parser, mPastSignatures); + } else if (tagName.equals("perms")) { + readGrantedPermissionsLPw(parser, su.grantedPermissions); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <shared-user>: " + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + + } else { + XmlUtils.skipCurrentTag(parser); + } + } + + private void readGrantedPermissionsLPw(XmlPullParser parser, HashSet<String> outPerms) + throws IOException, XmlPullParserException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("item")) { + String name = parser.getAttributeValue(null, "name"); + if (name != null) { + outPerms.add(name.intern()); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <perms> has" + " no name at " + + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <perms>: " + parser.getName()); + } + XmlUtils.skipCurrentTag(parser); + } + } + + private void readPreferredActivitiesLPw(XmlPullParser parser) throws XmlPullParserException, + IOException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("item")) { + PreferredActivity pa = new PreferredActivity(parser); + if (pa.mPref.getParseError() == null) { + mPreferredActivities.addFilter(pa); + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <preferred-activity> " + + pa.mPref.getParseError() + " at " + + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Unknown element under <preferred-activities>: " + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + } + + // Returns -1 if we could not find an available UserId to assign + private int newUserIdLPw(Object obj) { + // Let's be stupidly inefficient for now... + final int N = mUserIds.size(); + for (int i = 0; i < N; i++) { + if (mUserIds.get(i) == null) { + mUserIds.set(i, obj); + return PackageManagerService.FIRST_APPLICATION_UID + i; + } + } + + // None left? + if (N >= PackageManagerService.MAX_APPLICATION_UIDS) { + return -1; + } + + mUserIds.add(obj); + return PackageManagerService.FIRST_APPLICATION_UID + N; + } + + public PackageSetting getDisabledSystemPkgLPr(String name) { + PackageSetting ps = mDisabledSysPackages.get(name); + return ps; + } + + boolean isEnabledLPr(ComponentInfo componentInfo, int flags) { + if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { + return true; + } + final PackageSetting packageSettings = mPackages.get(componentInfo.packageName); + if (PackageManagerService.DEBUG_SETTINGS) { + Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = " + componentInfo.packageName + + " componentName = " + componentInfo.name); + Log.v(PackageManagerService.TAG, "enabledComponents: " + + Arrays.toString(packageSettings.enabledComponents.toArray())); + Log.v(PackageManagerService.TAG, "disabledComponents: " + + Arrays.toString(packageSettings.disabledComponents.toArray())); + } + if (packageSettings == null) { + return false; + } + if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED + || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled + && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) { + return false; + } + if (packageSettings.enabledComponents.contains(componentInfo.name)) { + return true; + } + if (packageSettings.disabledComponents.contains(componentInfo.name)) { + return false; + } + return componentInfo.enabled; + } + + String getInstallerPackageNameLPr(String packageName) { + final PackageSetting pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + return pkg.installerPackageName; + } + + int getApplicationEnabledSettingLPr(String packageName) { + final PackageSetting pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + return pkg.enabled; + } + + int getComponentEnabledSettingLPr(ComponentName componentName) { + final String packageName = componentName.getPackageName(); + final PackageSetting pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown component: " + componentName); + } + final String classNameStr = componentName.getClassName(); + return pkg.getCurrentEnabledStateLPr(classNameStr); + } + + boolean setPackageStoppedStateLPw(String packageName, boolean stopped, + boolean allowedByPermission, int uid) { + final PackageSetting pkgSetting = mPackages.get(packageName); + if (pkgSetting == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + if (!allowedByPermission && (uid != pkgSetting.userId)) { + throw new SecurityException( + "Permission Denial: attempt to change stopped state from pid=" + + Binder.getCallingPid() + + ", uid=" + uid + ", package uid=" + pkgSetting.userId); + } + if (DEBUG_STOPPED) { + if (stopped) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(TAG, "Stopping package " + packageName, e); + } + } + if (pkgSetting.stopped != stopped) { + pkgSetting.stopped = stopped; + pkgSetting.pkg.mSetStopped = stopped; + if (pkgSetting.notLaunched) { + if (pkgSetting.installerPackageName != null) { + PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, + pkgSetting.name, null, + pkgSetting.installerPackageName, null); + } + pkgSetting.notLaunched = false; + } + return true; + } + return false; + } + + void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) { + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + final Date date = new Date(); + boolean printedSomething = false; + for (final PackageSetting ps : mPackages.values()) { + if (packageName != null && !packageName.equals(ps.realName) + && !packageName.equals(ps.name)) { + continue; + } + + if (packageName != null) { + dumpState.setSharedUser(ps.sharedUser); + } + + if (!printedSomething) { + if (dumpState.onTitlePrinted()) + pw.println(" "); + pw.println("Packages:"); + printedSomething = true; + } + pw.print(" Package ["); + pw.print(ps.realName != null ? ps.realName : ps.name); + pw.print("] ("); + pw.print(Integer.toHexString(System.identityHashCode(ps))); + pw.println("):"); + + if (ps.realName != null) { + pw.print(" compat name="); + pw.println(ps.name); + } + + pw.print(" userId="); pw.print(ps.userId); + pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids)); + pw.print(" sharedUser="); pw.println(ps.sharedUser); + pw.print(" pkg="); pw.println(ps.pkg); + pw.print(" codePath="); pw.println(ps.codePathString); + pw.print(" resourcePath="); pw.println(ps.resourcePathString); + pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); + pw.print(" versionCode="); pw.println(ps.versionCode); + if (ps.pkg != null) { + pw.print(" versionName="); pw.println(ps.pkg.mVersionName); + pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); + pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion); + if (ps.pkg.mOperationPending) { + pw.println(" mOperationPending=true"); + } + pw.print(" supportsScreens=["); + boolean first = true; + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("small"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("medium"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("large"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("xlarge"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("resizeable"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("anyDensity"); + } + } + pw.println("]"); + pw.print(" timeStamp="); + date.setTime(ps.timeStamp); + pw.println(sdf.format(date)); + pw.print(" firstInstallTime="); + date.setTime(ps.firstInstallTime); + pw.println(sdf.format(date)); + pw.print(" lastUpdateTime="); + date.setTime(ps.lastUpdateTime); + pw.println(sdf.format(date)); + if (ps.installerPackageName != null) { + pw.print(" installerPackageName="); pw.println(ps.installerPackageName); + } + pw.print(" signatures="); pw.println(ps.signatures); + pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed); + pw.print(" haveGids="); pw.println(ps.haveGids); + pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); + pw.print(" installStatus="); pw.print(ps.installStatus); + pw.print(" stopped="); pw.print(ps.stopped); + pw.print(" enabled="); pw.println(ps.enabled); + if (ps.disabledComponents.size() > 0) { + pw.println(" disabledComponents:"); + for (String s : ps.disabledComponents) { + pw.print(" "); pw.println(s); + } + } + if (ps.enabledComponents.size() > 0) { + pw.println(" enabledComponents:"); + for (String s : ps.enabledComponents) { + pw.print(" "); pw.println(s); + } + } + if (ps.grantedPermissions.size() > 0) { + pw.println(" grantedPermissions:"); + for (String s : ps.grantedPermissions) { + pw.print(" "); pw.println(s); + } + } + } + + printedSomething = false; + if (mRenamedPackages.size() > 0) { + for (final HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) { + if (packageName != null && !packageName.equals(e.getKey()) + && !packageName.equals(e.getValue())) { + continue; + } + if (!printedSomething) { + if (dumpState.onTitlePrinted()) + pw.println(" "); + pw.println("Renamed packages:"); + printedSomething = true; + } + pw.print(" "); + pw.print(e.getKey()); + pw.print(" -> "); + pw.println(e.getValue()); + } + } + + printedSomething = false; + if (mDisabledSysPackages.size() > 0) { + for (final PackageSetting ps : mDisabledSysPackages.values()) { + if (packageName != null && !packageName.equals(ps.realName) + && !packageName.equals(ps.name)) { + continue; + } + if (!printedSomething) { + if (dumpState.onTitlePrinted()) + pw.println(" "); + pw.println("Hidden system packages:"); + printedSomething = true; + } + pw.print(" Package ["); + pw.print(ps.realName != null ? ps.realName : ps.name); + pw.print("] ("); + pw.print(Integer.toHexString(System.identityHashCode(ps))); + pw.println("):"); + if (ps.realName != null) { + pw.print(" compat name="); + pw.println(ps.name); + } + pw.print(" userId="); + pw.println(ps.userId); + pw.print(" sharedUser="); + pw.println(ps.sharedUser); + pw.print(" codePath="); + pw.println(ps.codePathString); + pw.print(" resourcePath="); + pw.println(ps.resourcePathString); + } + } + } + + void dumpPermissionsLPr(PrintWriter pw, String packageName, DumpState dumpState) { + boolean printedSomething = false; + for (BasePermission p : mPermissions.values()) { + if (packageName != null && !packageName.equals(p.sourcePackage)) { + continue; + } + if (!printedSomething) { + if (dumpState.onTitlePrinted()) + pw.println(" "); + pw.println("Permissions:"); + printedSomething = true; + } + pw.print(" Permission ["); pw.print(p.name); pw.print("] ("); + pw.print(Integer.toHexString(System.identityHashCode(p))); + pw.println("):"); + pw.print(" sourcePackage="); pw.println(p.sourcePackage); + pw.print(" uid="); pw.print(p.uid); + pw.print(" gids="); pw.print(PackageManagerService.arrayToString(p.gids)); + pw.print(" type="); pw.print(p.type); + pw.print(" prot="); pw.println(p.protectionLevel); + if (p.packageSetting != null) { + pw.print(" packageSetting="); pw.println(p.packageSetting); + } + if (p.perm != null) { + pw.print(" perm="); pw.println(p.perm); + } + } + } + + void dumpSharedUsersLPr(PrintWriter pw, String packageName, DumpState dumpState) { + boolean printedSomething = false; + for (SharedUserSetting su : mSharedUsers.values()) { + if (packageName != null && su != dumpState.getSharedUser()) { + continue; + } + if (!printedSomething) { + if (dumpState.onTitlePrinted()) + pw.println(" "); + pw.println("Shared users:"); + printedSomething = true; + } + pw.print(" SharedUser ["); + pw.print(su.name); + pw.print("] ("); + pw.print(Integer.toHexString(System.identityHashCode(su))); + pw.println("):"); + pw.print(" userId="); + pw.print(su.userId); + pw.print(" gids="); + pw.println(PackageManagerService.arrayToString(su.gids)); + pw.println(" grantedPermissions:"); + for (String s : su.grantedPermissions) { + pw.print(" "); + pw.println(s); + } + } + } + + void dumpReadMessagesLPr(PrintWriter pw, DumpState dumpState) { + pw.println("Settings parse messages:"); + pw.print(mReadMessages.toString()); + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/pm/SharedUserSetting.java b/services/java/com/android/server/pm/SharedUserSetting.java new file mode 100644 index 0000000..76826ea --- /dev/null +++ b/services/java/com/android/server/pm/SharedUserSetting.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.server.pm; + +import java.util.HashSet; + +/** + * Settings data for a particular shared user ID we know about. + */ +final class SharedUserSetting extends GrantedPermissions { + final String name; + + int userId; + + final HashSet<PackageSetting> packages = new HashSet<PackageSetting>(); + + final PackageSignatures signatures = new PackageSignatures(); + + SharedUserSetting(String _name, int _pkgFlags) { + super(_pkgFlags); + name = _name; + } + + @Override + public String toString() { + return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " " + + name + "/" + userId + "}"; + } +} diff --git a/services/jni/Android.mk b/services/jni/Android.mk index be37d5d..4e93fe2 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -34,7 +34,7 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libinput \ libskia \ - libsurfaceflinger_client \ + libgui \ libusbhost ifeq ($(TARGET_SIMULATOR),true) diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp index e64ec4e..1f80242 100644 --- a/services/jni/com_android_server_InputApplication.cpp +++ b/services/jni/com_android_server_InputApplication.cpp @@ -26,8 +26,6 @@ namespace android { static struct { - jclass clazz; - jfieldID inputApplicationHandle; jfieldID name; jfieldID dispatchingTimeoutNanos; @@ -69,25 +67,25 @@ void android_server_InputApplication_toNative( #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ LOG_FATAL_IF(! var, "Unable to find field " fieldName); int register_android_server_InputApplication(JNIEnv* env) { - FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/wm/InputApplication"); + jclass clazz; + FIND_CLASS(clazz, "com/android/server/wm/InputApplication"); GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle, - gInputApplicationClassInfo.clazz, + clazz, "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;"); - GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz, + GET_FIELD_ID(gInputApplicationClassInfo.name, clazz, "name", "Ljava/lang/String;"); GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos, - gInputApplicationClassInfo.clazz, + clazz, "dispatchingTimeoutNanos", "J"); return 0; } diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp index 3a1214f..9516964 100644 --- a/services/jni/com_android_server_InputApplicationHandle.cpp +++ b/services/jni/com_android_server_InputApplicationHandle.cpp @@ -26,8 +26,6 @@ namespace android { static struct { - jclass clazz; - jfieldID ptr; } gInputApplicationHandleClassInfo; @@ -98,8 +96,7 @@ static JNINativeMethod gInputApplicationHandleMethods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ @@ -110,9 +107,10 @@ int register_android_server_InputApplicationHandle(JNIEnv* env) { gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods)); LOG_FATAL_IF(res < 0, "Unable to register native methods."); - FIND_CLASS(gInputApplicationHandleClassInfo.clazz, "com/android/server/wm/InputApplicationHandle"); + jclass clazz; + FIND_CLASS(clazz, "com/android/server/wm/InputApplicationHandle"); - GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, gInputApplicationHandleClassInfo.clazz, + GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz, "ptr", "I"); return 0; diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 80dddc2..c022123 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -52,8 +52,6 @@ namespace android { static struct { - jclass clazz; - jmethodID notifyConfigurationChanged; jmethodID notifyLidSwitchChanged; jmethodID notifyInputChannelBroken; @@ -95,16 +93,12 @@ static struct { } gInputDeviceClassInfo; static struct { - jclass clazz; - jfieldID touchscreen; jfieldID keyboard; jfieldID navigation; } gConfigurationClassInfo; static struct { - jclass clazz; - jfieldID bitmap; jfieldID hotSpotX; jfieldID hotSpotY; @@ -606,6 +600,7 @@ void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationO android_server_InputApplication_toNative(env, applicationObj, &application); if (application.inputApplicationHandle != NULL) { mInputManager->getDispatcher()->setFocusedApplication(&application); + return; } } mInputManager->getDispatcher()->setFocusedApplication(NULL); @@ -1024,15 +1019,14 @@ static jint android_server_InputManager_nativeInjectInputEvent(JNIEnv* env, jcla return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent( & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis); } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) { - MotionEvent motionEvent; - status_t status = android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent); - if (status) { + const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj); + if (!motionEvent) { jniThrowRuntimeException(env, "Could not read contents of MotionEvent object."); return INPUT_EVENT_INJECTION_FAILED; } return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent( - & motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis); + motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis); } else { jniThrowRuntimeException(env, "Invalid input event type."); return INPUT_EVENT_INJECTION_FAILED; @@ -1226,8 +1220,7 @@ static JNINativeMethod gInputManagerMethods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ var = env->GetMethodID(clazz, methodName, methodDescriptor); \ @@ -1244,77 +1237,82 @@ int register_android_server_InputManager(JNIEnv* env) { // Callbacks - FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/wm/InputManager$Callbacks"); + jclass clazz; + FIND_CLASS(clazz, "com/android/server/wm/InputManager$Callbacks"); - GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, clazz, "notifyConfigurationChanged", "(J)V"); - GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, clazz, "notifyLidSwitchChanged", "(JZ)V"); - GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, clazz, "notifyInputChannelBroken", "(Lcom/android/server/wm/InputWindowHandle;)V"); - GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.notifyANR, clazz, "notifyANR", "(Lcom/android/server/wm/InputApplicationHandle;Lcom/android/server/wm/InputWindowHandle;)J"); - GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, clazz, "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I"); GET_METHOD_ID(gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff, - gCallbacksClassInfo.clazz, + clazz, "interceptMotionBeforeQueueingWhenScreenOff", "(I)I"); - GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, clazz, "interceptKeyBeforeDispatching", "(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)Z"); - GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, clazz, "dispatchUnhandledKey", "(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;"); - GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, clazz, "checkInjectEventsPermission", "(II)Z"); - GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, clazz, "filterTouchEvents", "()Z"); - GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, clazz, "filterJumpyTouchEvents", "()Z"); - GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyQuietTimeMillis, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyQuietTimeMillis, clazz, "getVirtualKeyQuietTimeMillis", "()I"); - GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, clazz, "getExcludedDeviceNames", "()[Ljava/lang/String;"); - GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatTimeout, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatTimeout, clazz, "getKeyRepeatTimeout", "()I"); - GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, clazz, "getKeyRepeatDelay", "()I"); - GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, clazz, "getMaxEventsPerSecond", "()I"); - GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, clazz, "getPointerLayer", "()I"); - GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, gCallbacksClassInfo.clazz, + GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, clazz, "getPointerIcon", "()Lcom/android/server/wm/InputManager$PointerIcon;"); // KeyEvent FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); + gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz)); + // MotionEvent FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent"); + gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz)); // InputDevice FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice"); + gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz)); GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz, "<init>", "()V"); @@ -1336,28 +1334,28 @@ int register_android_server_InputManager(JNIEnv* env) { // Configuration - FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration"); + FIND_CLASS(clazz, "android/content/res/Configuration"); - GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.touchscreen, clazz, "touchscreen", "I"); - GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.keyboard, clazz, "keyboard", "I"); - GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz, + GET_FIELD_ID(gConfigurationClassInfo.navigation, clazz, "navigation", "I"); // PointerIcon - FIND_CLASS(gPointerIconClassInfo.clazz, "com/android/server/wm/InputManager$PointerIcon"); + FIND_CLASS(clazz, "com/android/server/wm/InputManager$PointerIcon"); - GET_FIELD_ID(gPointerIconClassInfo.bitmap, gPointerIconClassInfo.clazz, + GET_FIELD_ID(gPointerIconClassInfo.bitmap, clazz, "bitmap", "Landroid/graphics/Bitmap;"); - GET_FIELD_ID(gPointerIconClassInfo.hotSpotX, gPointerIconClassInfo.clazz, + GET_FIELD_ID(gPointerIconClassInfo.hotSpotX, clazz, "hotSpotX", "F"); - GET_FIELD_ID(gPointerIconClassInfo.hotSpotY, gPointerIconClassInfo.clazz, + GET_FIELD_ID(gPointerIconClassInfo.hotSpotY, clazz, "hotSpotY", "F"); return 0; diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp index 8548b47..99f625c 100644 --- a/services/jni/com_android_server_InputWindow.cpp +++ b/services/jni/com_android_server_InputWindow.cpp @@ -28,8 +28,6 @@ namespace android { static struct { - jclass clazz; - jfieldID inputWindowHandle; jfieldID inputChannel; jfieldID name; @@ -136,71 +134,71 @@ void android_server_InputWindow_toNative( #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ LOG_FATAL_IF(! var, "Unable to find field " fieldName); int register_android_server_InputWindow(JNIEnv* env) { - FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/wm/InputWindow"); + jclass clazz; + FIND_CLASS(clazz, "com/android/server/wm/InputWindow"); - GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, clazz, "inputWindowHandle", "Lcom/android/server/wm/InputWindowHandle;"); - GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.inputChannel, clazz, "inputChannel", "Landroid/view/InputChannel;"); - GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.name, clazz, "name", "Ljava/lang/String;"); - GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, clazz, "layoutParamsFlags", "I"); - GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, clazz, "layoutParamsType", "I"); - GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, clazz, "dispatchingTimeoutNanos", "J"); - GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.frameLeft, clazz, "frameLeft", "I"); - GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.frameTop, clazz, "frameTop", "I"); - GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.frameRight, clazz, "frameRight", "I"); - GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.frameBottom, clazz, "frameBottom", "I"); - GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, clazz, "touchableRegion", "Landroid/graphics/Region;"); - GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.visible, clazz, "visible", "Z"); - GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, clazz, "canReceiveKeys", "Z"); - GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.hasFocus, clazz, "hasFocus", "Z"); - GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, clazz, "hasWallpaper", "Z"); - GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.paused, clazz, "paused", "Z"); - GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.layer, clazz, "layer", "I"); - GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.ownerPid, clazz, "ownerPid", "I"); - GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz, + GET_FIELD_ID(gInputWindowClassInfo.ownerUid, clazz, "ownerUid", "I"); return 0; } diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp index 5b74e43..aaf679c 100644 --- a/services/jni/com_android_server_InputWindowHandle.cpp +++ b/services/jni/com_android_server_InputWindowHandle.cpp @@ -27,8 +27,6 @@ namespace android { static struct { - jclass clazz; - jfieldID ptr; jfieldID inputApplicationHandle; } gInputWindowHandleClassInfo; @@ -108,8 +106,7 @@ static JNINativeMethod gInputWindowHandleMethods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ @@ -120,13 +117,14 @@ int register_android_server_InputWindowHandle(JNIEnv* env) { gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods)); LOG_FATAL_IF(res < 0, "Unable to register native methods."); - FIND_CLASS(gInputWindowHandleClassInfo.clazz, "com/android/server/wm/InputWindowHandle"); + jclass clazz; + FIND_CLASS(clazz, "com/android/server/wm/InputWindowHandle"); - GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, gInputWindowHandleClassInfo.clazz, + GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz, "ptr", "I"); GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle, - gInputWindowHandleClassInfo.clazz, + clazz, "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;"); return 0; diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp index 705be60..a389c11 100644 --- a/services/jni/com_android_server_PowerManagerService.cpp +++ b/services/jni/com_android_server_PowerManagerService.cpp @@ -35,8 +35,6 @@ namespace android { // ---------------------------------------------------------------------------- static struct { - jclass clazz; - jmethodID goToSleep; jmethodID userActivity; } gPowerManagerServiceClassInfo; @@ -144,8 +142,7 @@ static JNINativeMethod gPowerManagerServiceMethods[] = { #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); + LOG_FATAL_IF(! var, "Unable to find class " className); #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ var = env->GetMethodID(clazz, methodName, methodDescriptor); \ @@ -162,12 +159,13 @@ int register_android_server_PowerManagerService(JNIEnv* env) { // Callbacks - FIND_CLASS(gPowerManagerServiceClassInfo.clazz, "com/android/server/PowerManagerService"); + jclass clazz; + FIND_CLASS(clazz, "com/android/server/PowerManagerService"); - GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, gPowerManagerServiceClassInfo.clazz, + GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, clazz, "goToSleep", "(J)V"); - GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, gPowerManagerServiceClassInfo.clazz, + GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, clazz, "userActivity", "(JZIZ)V"); // Initialize diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk index 7e17fdd..c50e4a1 100644 --- a/services/sensorservice/Android.mk +++ b/services/sensorservice/Android.mk @@ -27,7 +27,7 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libgui -LOCAL_PRELINK_MODULE := false + LOCAL_MODULE:= libsensorservice diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 8a00a2e..9daaad8 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -41,7 +41,7 @@ LOCAL_SHARED_LIBRARIES := \ libGLESv1_CM \ libbinder \ libui \ - libsurfaceflinger_client + libgui LOCAL_C_INCLUDES := \ $(call include-path-for, corecg graphics) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 517c335..c4027e0 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -52,6 +52,7 @@ template <typename T> inline T min(T a, T b) { Layer::Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client) : LayerBaseClient(flinger, display, client), + mFormat(PIXEL_FORMAT_NONE), mGLExtensions(GLExtensions::getInstance()), mNeedsBlending(true), mNeedsDithering(false), @@ -59,7 +60,8 @@ Layer::Layer(SurfaceFlinger* flinger, mProtectedByApp(false), mTextureManager(), mBufferManager(mTextureManager), - mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false) + mWidth(0), mHeight(0), + mNeedsScaling(false), mFixedSize(false) { } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a9fa1ef..ea283c6 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -600,7 +600,7 @@ sp<FreezeLock> SurfaceFlinger::getFreezeLock() const } void SurfaceFlinger::computeVisibleRegions( - LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion) + const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion) { const GraphicPlane& plane(graphicPlane(0)); const Transform& planeTransform(plane.transform()); @@ -735,8 +735,7 @@ void SurfaceFlinger::commitTransaction() void SurfaceFlinger::handlePageFlip() { bool visibleRegions = mVisibleRegionsDirty; - LayerVector& currentLayers( - const_cast<LayerVector&>(mDrawingState.layersSortedByZ)); + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); visibleRegions |= lockPageFlip(currentLayers); const DisplayHardware& hw = graphicPlane(0).displayHardware(); @@ -748,9 +747,8 @@ void SurfaceFlinger::handlePageFlip() /* * rebuild the visible layer list */ + const size_t count = currentLayers.size(); mVisibleLayersSortedByZ.clear(); - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - size_t count = currentLayers.size(); mVisibleLayersSortedByZ.setCapacity(count); for (size_t i=0 ; i<count ; i++) { if (!currentLayers[i]->visibleRegionScreen.isEmpty()) @@ -2515,7 +2513,7 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const } break; } - if (++name >= SharedBufferStack::NUM_LAYERS_MAX) + if (++name >= int32_t(SharedBufferStack::NUM_LAYERS_MAX)) name = NO_MEMORY; } while(name >= 0); @@ -2562,7 +2560,7 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h void GraphicBufferAlloc::freeAllGraphicBuffersExcept(int bufIdx) { Mutex::Autolock _l(mLock); - if (0 <= bufIdx && bufIdx < mBuffers.size()) { + if (bufIdx >= 0 && size_t(bufIdx) < mBuffers.size()) { sp<GraphicBuffer> b(mBuffers[bufIdx]); mBuffers.clear(); mBuffers.add(b); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9566819..0964848 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -304,7 +304,7 @@ private: Vector< sp<LayerBase> >& ditchedLayers); void computeVisibleRegions( - LayerVector& currentLayers, + const LayerVector& currentLayers, Region& dirtyRegion, Region& wormholeRegion); @@ -371,7 +371,6 @@ private: // access must be protected by mStateLock mutable Mutex mStateLock; State mCurrentState; - State mDrawingState; volatile int32_t mTransactionFlags; volatile int32_t mTransactionCount; Condition mTransactionCV; @@ -395,6 +394,7 @@ private: // Can only accessed from the main thread, these members // don't need synchronization + State mDrawingState; Region mDirtyRegion; Region mDirtyRegionRemovedLayer; Region mInvalidRegion; diff --git a/services/surfaceflinger/tests/resize/Android.mk b/services/surfaceflinger/tests/resize/Android.mk index 24c2d01..d81679e 100644 --- a/services/surfaceflinger/tests/resize/Android.mk +++ b/services/surfaceflinger/tests/resize/Android.mk @@ -8,7 +8,7 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libui \ - libsurfaceflinger_client + libgui LOCAL_MODULE:= test-resize diff --git a/services/surfaceflinger/tests/screencap/Android.mk b/services/surfaceflinger/tests/screencap/Android.mk index 1cfb471..5cdd1a8 100644 --- a/services/surfaceflinger/tests/screencap/Android.mk +++ b/services/surfaceflinger/tests/screencap/Android.mk @@ -10,7 +10,7 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libskia \ libui \ - libsurfaceflinger_client + libgui LOCAL_MODULE:= test-screencap diff --git a/services/surfaceflinger/tests/surface/Android.mk b/services/surfaceflinger/tests/surface/Android.mk index ce0e807..c59060e 100644 --- a/services/surfaceflinger/tests/surface/Android.mk +++ b/services/surfaceflinger/tests/surface/Android.mk @@ -9,7 +9,7 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libbinder \ libui \ - libsurfaceflinger_client + libgui LOCAL_MODULE:= test-surface diff --git a/tests/BiDiTests/Android.mk b/tests/BiDiTests/Android.mk new file mode 100644 index 0000000..ae29fc2 --- /dev/null +++ b/tests/BiDiTests/Android.mk @@ -0,0 +1,27 @@ +# 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := BiDiTests + +LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml new file mode 100644 index 0000000..346ace8 --- /dev/null +++ b/tests/BiDiTests/AndroidManifest.xml @@ -0,0 +1,36 @@ +<?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. +--> + +<!-- Declare the contents of this Android application. The namespace + attribute brings in the Android platform namespace, and the package + supplies a unique name for the application. When writing your + own application, the package name must be changed from "com.example.*" + to come from a domain that you own or have control over. --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.bidi" + android:versionCode="1" + android:versionName="1.0"> + + <application android:label="BiDiTests"> + <activity android:name="BiDiTestActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> +</manifest>
\ No newline at end of file diff --git a/tests/BiDiTests/proguard.flags b/tests/BiDiTests/proguard.flags new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/BiDiTests/proguard.flags diff --git a/tests/BiDiTests/res/layout/biditest_main.xml b/tests/BiDiTests/res/layout/biditest_main.xml new file mode 100644 index 0000000..9f77ad2 --- /dev/null +++ b/tests/BiDiTests/res/layout/biditest_main.xml @@ -0,0 +1,58 @@ +<?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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Button android:id="@+id/button" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:onClick="onButtonClick" + android:text="@string/button_text" + android:textSize="32dip" + /> + + <TextView android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="32dip" + android:text="@string/textview_text" + /> + + <EditText android:id="@+id/textview" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:textSize="32dip" + android:text="@string/edittext_text" + /> + + </LinearLayout> + + <view class="com.android.bidi.BiDiTestView" + android:id="@+id/main" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="#FF0000" + /> + +</LinearLayout>
\ No newline at end of file diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml new file mode 100644 index 0000000..ecff76e --- /dev/null +++ b/tests/BiDiTests/res/values/strings.xml @@ -0,0 +1,26 @@ +<!-- 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> + <string name="button_text">Button</string> + <string name="textview_text">This is a text for a TextView</string> + <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string> + <string name="normal_text">Normal String</string> + <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string> + <string name="arabic_text">لا</string> + <string name="chinese_text">利比亚局势或影响美俄关系发展</string> + <string name="italic_text">Italic String</string> + <string name="bold_text">Bold String</string> + <string name="bold_italic_text">Bold Italic String</string> +</resources>
\ No newline at end of file diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java new file mode 100644 index 0000000..3d7dd81 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.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.bidi; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.View; + +public class BiDiTestActivity extends Activity { + + static final String TAG = "BiDiTestActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.biditest_main); + } + + @Override + protected void onResume() { + super.onResume(); + } + + public void onButtonClick(View v) { + Log.v(TAG, "onButtonClick"); + } +}
\ No newline at end of file diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java new file mode 100644 index 0000000..e9b6fa6 --- /dev/null +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java @@ -0,0 +1,190 @@ +/* + * 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.bidi; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; + +public class BiDiTestView extends View { + + private static final String TAG = "BiDiTestView"; + + private static final int BORDER_PADDING = 4; + private static final int TEXT_PADDING = 16; + private static final int TEXT_SIZE = 32; + private static final int ORIGIN = 48; + private static final int DELTA_Y = TEXT_SIZE; + + private static final float DEFAULT_ITALIC_SKEW_X = -0.25f; + + private Paint paint = new Paint(); + private Rect rect = new Rect(); + + private String NORMAL_TEXT; + private String NORMAL_LONG_TEXT; + private String ITALIC_TEXT; + private String BOLD_TEXT; + private String BOLD_ITALIC_TEXT; + private String ARABIC_TEXT; + private String CHINESE_TEXT; + + private Typeface typeface; + + public BiDiTestView(Context context) { + super(context); + init(context); + } + + public BiDiTestView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public BiDiTestView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context); + } + + private void init(Context context) { + NORMAL_TEXT = context.getString(R.string.normal_text); + NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text); + ITALIC_TEXT = context.getString(R.string.italic_text); + BOLD_TEXT = context.getString(R.string.bold_text); + BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text); + ARABIC_TEXT = context.getString(R.string.arabic_text); + CHINESE_TEXT = context.getString(R.string.chinese_text); + + typeface = paint.getTypeface(); + paint.setAntiAlias(true); + } + + @Override + public void onDraw(Canvas canvas) { + drawInsideRect(canvas, Color.BLACK); + + int deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN, paint, typeface, + false, false, Paint.DIRECTION_LTR); + deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface, + true, false, Paint.DIRECTION_LTR); + deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface, + false, true, Paint.DIRECTION_LTR); + deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface, + true, true, Paint.DIRECTION_LTR); + + // Test with a long string + deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * DELTA_Y, paint, typeface, + false, false, Paint.DIRECTION_LTR); + + // Test Arabic ligature + deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 4 * DELTA_Y, paint, typeface, + false, false, Paint.DIRECTION_RTL); + + // Test Chinese + deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 6 * DELTA_Y, paint, typeface, + false, false, Paint.DIRECTION_LTR); + } + + private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface, + boolean isItalic, boolean isBold, int dir) { + paint.setTypeface(typeface); + + // Set paint properties + boolean oldFakeBold = paint.isFakeBoldText(); + paint.setFakeBoldText(isBold); + + float oldTextSkewX = paint.getTextSkewX(); + if (isItalic) { + paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X); + } + + drawTextWithCanvasDrawText(text, canvas, x, y, TEXT_SIZE, Color.WHITE); + + int length = text.length(); + float[] advances = new float[length]; + float textWidth = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0); + + logAdvances(text, textWidth, advances); + drawBoxAroundText(canvas, x, y, textWidth, TEXT_SIZE, Color.RED); + + paint.setColor(Color.WHITE); + char[] glyphs = new char[2*length]; + int count = getGlyphs(text, glyphs, dir); + + logGlypths(glyphs, count); + drawTextWithDrawGlyph(canvas, glyphs, count, x, y + DELTA_Y); + + // Restore old paint properties + paint.setFakeBoldText(oldFakeBold); + paint.setTextSkewX(oldTextSkewX); + + return (int) Math.ceil(textWidth) + TEXT_PADDING; + } + + private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) { + canvas.drawGlyphs(glyphs, 0, count, x, y, paint); + } + + private void logGlypths(char[] glyphs, int count) { + Log.v(TAG, "GlyphIds - count=" + count); + for (int n = 0; n < count; n++) { + Log.v(TAG, "GlyphIds - Id[" + n + "]="+ (int)glyphs[n]); + } + } + + private int getGlyphs(String text, char[] glyphs, int dir) { +// int dir = 1; // Paint.DIRECTION_LTR; + return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs); + } + + private void drawInsideRect(Canvas canvas, int color) { + paint.setColor(color); + int width = getWidth(); + int height = getHeight(); + rect.set(BORDER_PADDING, BORDER_PADDING, width - BORDER_PADDING, height - BORDER_PADDING); + canvas.drawRect(rect, paint); + } + + private void drawTextWithCanvasDrawText(String text, Canvas canvas, + float x, float y, float textSize, int color) { + paint.setColor(color); + paint.setTextSize(textSize); + canvas.drawText(text, x, y, paint); + } + + private void drawBoxAroundText(Canvas canvas, int x, int y, float textWidth, int textSize, + int color) { + paint.setColor(color); + canvas.drawLine(x, y - textSize, x, y + 8, paint); + canvas.drawLine(x, y + 8, x + textWidth, y + 8, paint); + canvas.drawLine(x + textWidth, y - textSize, x + textWidth, y + 8, paint); + } + + private void logAdvances(String text, float textWidth, float[] advances) { + Log.v(TAG, "Advances for text: " + text + " total=" + textWidth); + int length = advances.length; + for(int n=0; n<length; n++){ + Log.v(TAG, "adv[" + n + "]=" + advances[n]); + } + } +} diff --git a/tests/BrowserTestPlugin/jni/Android.mk b/tests/BrowserTestPlugin/jni/Android.mk index 95a21e9..a0d647b 100644 --- a/tests/BrowserTestPlugin/jni/Android.mk +++ b/tests/BrowserTestPlugin/jni/Android.mk @@ -41,7 +41,7 @@ LOCAL_C_INCLUDES += \ external/webkit/WebKit/android/plugins LOCAL_CFLAGS += -fvisibility=hidden -LOCAL_PRELINK_MODULE := false + LOCAL_MODULE := libtestplugin LOCAL_MODULE_TAGS := tests diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index e82f9aa..2afc935 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -34,6 +34,15 @@ </activity> <activity + android:name="BitmapMutateActivity" + android:label="_BitmapMutate"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity android:name="BitmapMeshLayerActivity" android:label="_BitmapMeshLayer"> <intent-filter> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java new file mode 100644 index 0000000..db9017c --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010 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.test.hwui; + +import android.animation.ObjectAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class BitmapMutateActivity extends Activity { + private static final int PATTERN_SIZE = 400; + + private ObjectAnimator mAnimator; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final BitmapsView view = new BitmapsView(this); + final FrameLayout layout = new FrameLayout(this); + + layout.addView(view, new FrameLayout.LayoutParams(480, 800, Gravity.CENTER)); + + setContentView(layout); + + mAnimator = ObjectAnimator.ofInt(view, "offset", 0, PATTERN_SIZE - 1); + mAnimator.setDuration(1500); + mAnimator.setRepeatCount(ObjectAnimator.INFINITE); + mAnimator.setRepeatMode(ObjectAnimator.REVERSE); + mAnimator.start(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mAnimator.cancel(); + } + + static class BitmapsView extends View { + private final Paint mBitmapPaint; + private final Bitmap mBitmap1; + private final int[] mPixels; + + private int mOffset; + private int mSlice; + private static final int[] mShifts = new int[] { 16, 8, 0 }; + + BitmapsView(Context c) { + super(c); + + mBitmap1 = Bitmap.createBitmap(PATTERN_SIZE, PATTERN_SIZE, Bitmap.Config.ARGB_8888); + mBitmapPaint = new Paint(); + + mPixels = new int[mBitmap1.getWidth() * mBitmap1.getHeight()]; + mSlice = mBitmap1.getWidth() / 3; + } + + public void setOffset(int offset) { + mOffset = offset; + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int width = mBitmap1.getWidth(); + int height = mBitmap1.getHeight(); + + canvas.translate((getWidth() - width) / 2, (getHeight() - height) / 2); + + for (int x = 0; x < width; x++) { + int color = 0xff000000; + int i = x == 0 ? 0 : x - 1; + color |= (int) ((0xff * ((i + mOffset) % mSlice) / (float) mSlice)) << + mShifts[i / mSlice]; + for (int y = 0; y < height; y++) { + mPixels[y * width + x] = color; + } + } + + mBitmap1.setPixels(mPixels, 0, width, 0, 0, width, height); + canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java index 8ca842e..4233367 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java @@ -16,6 +16,7 @@ package com.android.test.hwui; +import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; @@ -29,13 +30,26 @@ import android.view.View; @SuppressWarnings({"UnusedDeclaration"}) public class LinesActivity extends Activity { + private ObjectAnimator mAnimator; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setBackgroundDrawable(new ColorDrawable(0xffffffff)); final LinesView view = new LinesView(this); - //view.setAlpha(0.80f); setContentView(view); + + mAnimator = ObjectAnimator.ofFloat(view, "offset", 0.0f, 15.0f); + mAnimator.setDuration(1500); + mAnimator.setRepeatCount(ObjectAnimator.INFINITE); + mAnimator.setRepeatMode(ObjectAnimator.REVERSE); + mAnimator.start(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mAnimator.cancel(); } public static class LinesView extends View { @@ -50,6 +64,8 @@ public class LinesActivity extends Activity { private final Paint mAlphaPaint; private final Paint mHairLinePaint; + private float mOffset; + public LinesView(Context c) { super(c); @@ -89,11 +105,16 @@ public class LinesActivity extends Activity { 352.0f, 400.0f, 352.0f, 500.0f }; } + + public void setOffset(float offset) { + mOffset = offset; + invalidate(); + } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - + canvas.save(); canvas.translate(100.0f, 20.0f); @@ -103,6 +124,12 @@ public class LinesActivity extends Activity { mLargePaint.setShader(mShader); canvas.drawLine(42.0f, 0.0f, 222.0f, 400.0f, mLargePaint); + for (int x = 0; x < 20; x++) { + for (int y = 0; y < 20; y++) { + canvas.drawPoint(500.0f + x * (15.0f + mOffset), + y * (15.0f + mOffset), mLargePaint); + } + } mLargePaint.setShader(null); canvas.drawLines(mPoints, mAlphaPaint); @@ -120,6 +147,7 @@ public class LinesActivity extends Activity { canvas.restore(); + canvas.save(); canvas.scale(10.0f, 10.0f); canvas.drawLine(50.0f, 40.0f, 10.0f, 40.0f, mSmallPaint); canvas.drawLine(10.0f, 50.0f, 50.0f, 50.0f, mSmallPaint); diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 5339566..10815a1 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -2607,6 +2607,9 @@ ResourceFilter::match(const ResTable_config& config) const if (!match(AXIS_SCREENSIZE, config.screenSize)) { return false; } + if (!match(AXIS_SCREENLAYOUTSIZE, config.screenLayout&ResTable_config::MASK_SCREENSIZE)) { + return false; + } if (!match(AXIS_VERSION, config.version)) { return false; } diff --git a/tools/velocityplot/velocityplot.py b/tools/velocityplot/velocityplot.py new file mode 100755 index 0000000..421bed4 --- /dev/null +++ b/tools/velocityplot/velocityplot.py @@ -0,0 +1,289 @@ +#!/usr/bin/env python2.6 +# +# 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. +# + +# +# Plots debug log output from VelocityTracker. +# Enable DEBUG_VELOCITY to print the output. +# +# This code supports side-by-side comparison of two algorithms. +# The old algorithm should be modified to emit debug log messages containing +# the word "OLD". +# + +import numpy as np +import matplotlib.pyplot as plot +import subprocess +import re +import fcntl +import os +import errno +import bisect +from datetime import datetime, timedelta + +# Parameters. +timespan = 15 # seconds total span shown +scrolljump = 5 # seconds jump when scrolling +timeticks = 1 # seconds between each time tick + +# Non-blocking stream wrapper. +class NonBlockingStream: + def __init__(self, stream): + fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK) + self.stream = stream + self.buffer = '' + self.pos = 0 + + def readline(self): + while True: + index = self.buffer.find('\n', self.pos) + if index != -1: + result = self.buffer[self.pos:index] + self.pos = index + 1 + return result + + self.buffer = self.buffer[self.pos:] + self.pos = 0 + try: + chunk = os.read(self.stream.fileno(), 4096) + except OSError, e: + if e.errno == errno.EAGAIN: + return None + raise e + if len(chunk) == 0: + if len(self.buffer) == 0: + raise(EOFError) + else: + result = self.buffer + self.buffer = '' + self.pos = 0 + return result + self.buffer += chunk + +# Plotter +class Plotter: + def __init__(self, adbout): + self.adbout = adbout + + self.fig = plot.figure(1) + self.fig.suptitle('Velocity Tracker', fontsize=12) + self.fig.set_dpi(96) + self.fig.set_size_inches(16, 12, forward=True) + + self.velocity_x = self._make_timeseries() + self.velocity_y = self._make_timeseries() + self.velocity_magnitude = self._make_timeseries() + self.velocity_axes = self._add_timeseries_axes( + 1, 'Velocity', 'px/s', [-5000, 5000], + yticks=range(-5000, 5000, 1000)) + self.velocity_line_x = self._add_timeseries_line( + self.velocity_axes, 'vx', 'red') + self.velocity_line_y = self._add_timeseries_line( + self.velocity_axes, 'vy', 'green') + self.velocity_line_magnitude = self._add_timeseries_line( + self.velocity_axes, 'magnitude', 'blue') + self._add_timeseries_legend(self.velocity_axes) + + shared_axis = self.velocity_axes + + self.old_velocity_x = self._make_timeseries() + self.old_velocity_y = self._make_timeseries() + self.old_velocity_magnitude = self._make_timeseries() + self.old_velocity_axes = self._add_timeseries_axes( + 2, 'Old Algorithm Velocity', 'px/s', [-5000, 5000], + sharex=shared_axis, + yticks=range(-5000, 5000, 1000)) + self.old_velocity_line_x = self._add_timeseries_line( + self.old_velocity_axes, 'vx', 'red') + self.old_velocity_line_y = self._add_timeseries_line( + self.old_velocity_axes, 'vy', 'green') + self.old_velocity_line_magnitude = self._add_timeseries_line( + self.old_velocity_axes, 'magnitude', 'blue') + self._add_timeseries_legend(self.old_velocity_axes) + + self.timer = self.fig.canvas.new_timer(interval=100) + self.timer.add_callback(lambda: self.update()) + self.timer.start() + + self.timebase = None + self._reset_parse_state() + + # Initialize a time series. + def _make_timeseries(self): + return [[], []] + + # Add a subplot to the figure for a time series. + def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None): + num_graphs = 2 + height = 0.9 / num_graphs + top = 0.95 - height * index + axes = self.fig.add_axes([0.1, top, 0.8, height], + xscale='linear', + xlim=[0, timespan], + ylabel=ylabel, + yscale='linear', + ylim=ylim, + sharex=sharex) + axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold') + axes.set_xlabel('time (s)', fontsize=10, fontweight='bold') + axes.set_ylabel(ylabel, fontsize=10, fontweight='bold') + axes.set_xticks(range(0, timespan + 1, timeticks)) + axes.set_yticks(yticks) + axes.grid(True) + + for label in axes.get_xticklabels(): + label.set_fontsize(9) + for label in axes.get_yticklabels(): + label.set_fontsize(9) + + return axes + + # Add a line to the axes for a time series. + def _add_timeseries_line(self, axes, label, color, linewidth=1): + return axes.plot([], label=label, color=color, linewidth=linewidth)[0] + + # Add a legend to a time series. + def _add_timeseries_legend(self, axes): + axes.legend( + loc='upper left', + bbox_to_anchor=(1.01, 1), + borderpad=0.1, + borderaxespad=0.1, + prop={'size': 10}) + + # Resets the parse state. + def _reset_parse_state(self): + self.parse_velocity_x = None + self.parse_velocity_y = None + self.parse_velocity_magnitude = None + self.parse_old_velocity_x = None + self.parse_old_velocity_y = None + self.parse_old_velocity_magnitude = None + + # Update samples. + def update(self): + timeindex = 0 + while True: + try: + line = self.adbout.readline() + except EOFError: + plot.close() + return + if line is None: + break + print line + + try: + timestamp = self._parse_timestamp(line) + except ValueError, e: + continue + if self.timebase is None: + self.timebase = timestamp + delta = timestamp - self.timebase + timeindex = delta.seconds + delta.microseconds * 0.000001 + + if line.find(': position') != -1: + self.parse_velocity_x = self._get_following_number(line, 'vx=') + self.parse_velocity_y = self._get_following_number(line, 'vy=') + self.parse_velocity_magnitude = self._get_following_number(line, 'speed=') + self._append(self.velocity_x, timeindex, self.parse_velocity_x) + self._append(self.velocity_y, timeindex, self.parse_velocity_y) + self._append(self.velocity_magnitude, timeindex, self.parse_velocity_magnitude) + + if line.find(': OLD') != -1: + self.parse_old_velocity_x = self._get_following_number(line, 'vx=') + self.parse_old_velocity_y = self._get_following_number(line, 'vy=') + self.parse_old_velocity_magnitude = self._get_following_number(line, 'speed=') + self._append(self.old_velocity_x, timeindex, self.parse_old_velocity_x) + self._append(self.old_velocity_y, timeindex, self.parse_old_velocity_y) + self._append(self.old_velocity_magnitude, timeindex, self.parse_old_velocity_magnitude) + + # Scroll the plots. + if timeindex > timespan: + bottom = int(timeindex) - timespan + scrolljump + self.timebase += timedelta(seconds=bottom) + self._scroll(self.velocity_x, bottom) + self._scroll(self.velocity_y, bottom) + self._scroll(self.velocity_magnitude, bottom) + self._scroll(self.old_velocity_x, bottom) + self._scroll(self.old_velocity_y, bottom) + self._scroll(self.old_velocity_magnitude, bottom) + + # Redraw the plots. + self.velocity_line_x.set_data(self.velocity_x) + self.velocity_line_y.set_data(self.velocity_y) + self.velocity_line_magnitude.set_data(self.velocity_magnitude) + self.old_velocity_line_x.set_data(self.old_velocity_x) + self.old_velocity_line_y.set_data(self.old_velocity_y) + self.old_velocity_line_magnitude.set_data(self.old_velocity_magnitude) + + self.fig.canvas.draw_idle() + + # Scroll a time series. + def _scroll(self, timeseries, bottom): + bottom_index = bisect.bisect_left(timeseries[0], bottom) + del timeseries[0][:bottom_index] + del timeseries[1][:bottom_index] + for i, timeindex in enumerate(timeseries[0]): + timeseries[0][i] = timeindex - bottom + + # Extract a word following the specified prefix. + def _get_following_word(self, line, prefix): + prefix_index = line.find(prefix) + if prefix_index == -1: + return None + start_index = prefix_index + len(prefix) + delim_index = line.find(',', start_index) + if delim_index == -1: + return line[start_index:] + else: + return line[start_index:delim_index] + + # Extract a number following the specified prefix. + def _get_following_number(self, line, prefix): + word = self._get_following_word(line, prefix) + if word is None: + return None + return float(word) + + # Add a value to a time series. + def _append(self, timeseries, timeindex, number): + timeseries[0].append(timeindex) + timeseries[1].append(number) + + # Parse the logcat timestamp. + # Timestamp has the form '01-21 20:42:42.930' + def _parse_timestamp(self, line): + return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f') + +# Notice +print "Velocity Tracker plotting tool" +print "-----------------------------------------\n" +print "Please enable debug logging and recompile the code." + +# Start adb. +print "Starting adb logcat.\n" + +adb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'Input:*', 'VelocityTracker:*'], + stdout=subprocess.PIPE) +adbout = NonBlockingStream(adb.stdout) + +# Prepare plotter. +plotter = Plotter(adbout) +plotter.update() + +# Main loop. +plot.show() diff --git a/voip/jni/rtp/Android.mk b/voip/jni/rtp/Android.mk index 76c43ba..61680a2 100644 --- a/voip/jni/rtp/Android.mk +++ b/voip/jni/rtp/Android.mk @@ -53,6 +53,6 @@ LOCAL_C_INCLUDES += \ LOCAL_CFLAGS += -fvisibility=hidden -LOCAL_PRELINK_MODULE := false + include $(BUILD_SHARED_LIBRARY) diff --git a/voip/jni/rtp/AudioCodec.cpp b/voip/jni/rtp/AudioCodec.cpp index 2267ea0..c75fbc9 100644 --- a/voip/jni/rtp/AudioCodec.cpp +++ b/voip/jni/rtp/AudioCodec.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <string.h> +#include <strings.h> #include "AudioCodec.h" diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 2e49a77..d40f146 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1193,16 +1193,19 @@ public class WifiManager { * Acquiring a WifiLock will keep the radio on until the lock is released. Multiple * applications may hold WifiLocks, and the radio will only be allowed to turn off when no * WifiLocks are held in any application. - * + * <p> * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or * could function over a mobile network, if available. A program that needs to download large * files should hold a WifiLock to ensure that the download will complete, but a program whose * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely * affecting battery life. - * + * <p> * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane * Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device * is idle. + * <p> + * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK} + * permission in an {@code <uses-permission>} element of the application's manifest. */ public class WifiLock { private String mTag; |