Update from https://crrev.com/305340 Added a few #includes of base/compiler_specific.h for upstream cleanup. Changed callers for cc::BeginFrameArgs and cc::RendererSettings API changes. Review URL: https://codereview.chromium.org/754433003
diff --git a/.clang-format b/.clang-format index a7d210d..53f0da3 100644 --- a/.clang-format +++ b/.clang-format
@@ -16,5 +16,7 @@ AllowShortBlocksOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: true +BinPackArguments: true +BinPackParameters: true BreakBeforeBinaryOperators: NonAssignment Cpp11BracedListStyle: false # but see http://llvm.org/PR21457
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp index 323d79e..de3b273 100644 --- a/base/allocator/allocator.gyp +++ b/base/allocator/allocator.gyp
@@ -8,7 +8,7 @@ # This code gets run a lot and debugged rarely, so it should be fast # by default. See http://crbug.com/388949. 'debug_optimize': '2', - 'win_debug_Optimization': '2', + 'win_debug_Optimization': '0', # Run time checks are incompatible with any level of optimizations. 'win_debug_RuntimeChecks': '0', },
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java index 2af146b..8b2438c 100644 --- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java +++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -7,7 +7,6 @@ import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.app.ActivityOptions; -import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -27,9 +26,6 @@ * Utility class to use new APIs that were added after ICS (API level 14). */ public class ApiCompatibilityUtils { - - private static final String TAG = "ApiCompatibilityUtils"; - private ApiCompatibilityUtils() { } @@ -369,18 +365,6 @@ } /** - * @see android.app.Notification.Builder#setLocalOnly(boolean) - */ - @SuppressWarnings("deprecation") - public static Notification build(Notification.Builder builder) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - return builder.build(); - } else { - return builder.getNotification(); - } - } - - /** * @see android.provider.Settings.Global#DEVICE_PROVISIONED */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
diff --git a/base/android/java/src/org/chromium/base/CommandLine.java b/base/android/java/src/org/chromium/base/CommandLine.java index b353ec4..406f36b 100644 --- a/base/android/java/src/org/chromium/base/CommandLine.java +++ b/base/android/java/src/org/chromium/base/CommandLine.java
@@ -86,7 +86,7 @@ } private static final AtomicReference<CommandLine> sCommandLine = - new AtomicReference<CommandLine>(); + new AtomicReference<CommandLine>(); /** * @returns true if the command line has already been initialized. @@ -149,8 +149,8 @@ char currentQuote = noQuote; for (char c : buffer) { // Detect start or end of quote block. - if ((currentQuote == noQuote && (c == singleQuote || c == doubleQuote)) || - c == currentQuote) { + if ((currentQuote == noQuote && (c == singleQuote || c == doubleQuote)) + || c == currentQuote) { if (arg != null && arg.length() > 0 && arg.charAt(arg.length() - 1) == '\\') { // Last char was a backslash; pop it, and treat c as a literal. arg.setCharAt(arg.length() - 1, c);
diff --git a/base/android/java/src/org/chromium/base/LocaleUtils.java b/base/android/java/src/org/chromium/base/LocaleUtils.java index 4f97d3a..82b2c8f 100644 --- a/base/android/java/src/org/chromium/base/LocaleUtils.java +++ b/base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -47,9 +47,9 @@ @CalledByNative private static String getDefaultCountryCode() { CommandLine commandLine = CommandLine.getInstance(); - return commandLine.hasSwitch(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL) ? - commandLine.getSwitchValue(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL) : - Locale.getDefault().getCountry(); + return commandLine.hasSwitch(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL) + ? commandLine.getSwitchValue(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL) + : Locale.getDefault().getCountry(); } }
diff --git a/base/android/java/src/org/chromium/base/MemoryPressureListener.java b/base/android/java/src/org/chromium/base/MemoryPressureListener.java index 28d9651..e7c2030 100644 --- a/base/android/java/src/org/chromium/base/MemoryPressureListener.java +++ b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
@@ -86,8 +86,8 @@ public static void maybeNotifyMemoryPresure(int level) { if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { nativeOnMemoryPressure(MemoryPressureLevel.CRITICAL); - } else if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND || - level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) { + } else if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND + || level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) { // Don't notifiy on TRIM_MEMORY_UI_HIDDEN, since this class only // dispatches actionable memory pressure signals to native. nativeOnMemoryPressure(MemoryPressureLevel.MODERATE);
diff --git a/base/android/java/src/org/chromium/base/ObserverList.java b/base/android/java/src/org/chromium/base/ObserverList.java index c2bb902..e812b0d 100644 --- a/base/android/java/src/org/chromium/base/ObserverList.java +++ b/base/android/java/src/org/chromium/base/ObserverList.java
@@ -204,8 +204,8 @@ @Override public boolean hasNext() { int lookupIndex = mIndex; - while (lookupIndex < mListEndMarker && - ObserverList.this.getObserverAt(lookupIndex) == null) { + while (lookupIndex < mListEndMarker + && ObserverList.this.getObserverAt(lookupIndex) == null) { lookupIndex++; } if (lookupIndex < mListEndMarker) return true;
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java index b2c860f..d70c0cc 100644 --- a/base/android/java/src/org/chromium/base/PathUtils.java +++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -75,8 +75,8 @@ @CalledByNative private static String getNativeLibraryDirectory(Context appContext) { ApplicationInfo ai = appContext.getApplicationInfo(); - if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 || - (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 + || (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { return ai.nativeLibraryDir; }
diff --git a/base/android/java/src/org/chromium/base/PowerMonitor.java b/base/android/java/src/org/chromium/base/PowerMonitor.java index 316d6cc..3d0ed48 100644 --- a/base/android/java/src/org/chromium/base/PowerMonitor.java +++ b/base/android/java/src/org/chromium/base/PowerMonitor.java
@@ -31,11 +31,11 @@ // would be too aggressive. An Android activity can be in the "paused" state quite often. This // can happen when a dialog window shows up for instance. private static final Runnable sSuspendTask = new Runnable() { - @Override - public void run() { - nativeOnMainActivitySuspended(); - } - }; + @Override + public void run() { + nativeOnMainActivitySuspended(); + } + }; public static void createForTests(Context context) { // Applications will create this once the JNI side has been fully wired up both sides. For @@ -71,8 +71,8 @@ } int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); // If we're not plugged, assume we're running on battery power. - sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB && - chargePlug != BatteryManager.BATTERY_PLUGGED_AC; + sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB + && chargePlug != BatteryManager.BATTERY_PLUGGED_AC; nativeOnBatteryChargingChanged(); }
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java index 8813a6c..2a8deeb 100644 --- a/base/android/java/src/org/chromium/base/ThreadUtils.java +++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -32,9 +32,9 @@ public static void setUiThread(Looper looper) { synchronized (sLock) { if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) { - throw new RuntimeException("UI thread looper is already set to " + - sUiThreadHandler.getLooper() + " (Main thread looper is " + - Looper.getMainLooper() + "), cannot set to new looper " + looper); + throw new RuntimeException("UI thread looper is already set to " + + sUiThreadHandler.getLooper() + " (Main thread looper is " + + Looper.getMainLooper() + "), cannot set to new looper " + looper); } else { sUiThreadHandler = new Handler(looper); }
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java index b67d32d..1c7e534 100644 --- a/base/android/java/src/org/chromium/base/TraceEvent.java +++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -158,8 +158,8 @@ // Holder for monitor avoids unnecessary construction on non-debug runs private static final class LooperMonitorHolder { private static final BasicLooperMonitor sInstance = - CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_IDLE_TRACING) ? - new IdleTracingLooperMonitor() : new BasicLooperMonitor(); + CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_IDLE_TRACING) + ? new IdleTracingLooperMonitor() : new BasicLooperMonitor(); }
diff --git a/base/android/javatests/src/org/chromium/base/CommandLineTest.java b/base/android/javatests/src/org/chromium/base/CommandLineTest.java index 4300467..2b1a967 100644 --- a/base/android/javatests/src/org/chromium/base/CommandLineTest.java +++ b/base/android/javatests/src/org/chromium/base/CommandLineTest.java
@@ -113,8 +113,8 @@ toParse = " \t\n"; checkTokenizer(expected, toParse); - toParse = " \"a'b\" 'c\"d' \"e\\\"f\" 'g\\'h' \"i\\'j\" 'k\\\"l'" + - " m\"n\\'o\"p q'r\\\"s't"; + toParse = " \"a'b\" 'c\"d' \"e\\\"f\" 'g\\'h' \"i\\'j\" 'k\\\"l'" + + " m\"n\\'o\"p q'r\\\"s't"; expected = new String[] { "a'b", "c\"d", "e\"f",
diff --git a/base/bind_internal.h b/base/bind_internal.h index ae17ebf..2142797 100644 --- a/base/bind_internal.h +++ b/base/bind_internal.h
@@ -51,18 +51,15 @@ // Types: // RunnableAdapter<> -- Wraps the various "function" pointer types into an // object that adheres to the Runnable interface. -// There are |3*ARITY| RunnableAdapter types. // FunctionTraits<> -- Type traits that unwrap a function signature into a // a set of easier to use typedefs. Used mainly for // compile time asserts. // There are |ARITY| FunctionTraits types. // ForceVoidReturn<> -- Helper class for translating function signatures to // equivalent forms with a "void" return type. -// There are |ARITY| ForceVoidReturn types. // FunctorTraits<> -- Type traits used determine the correct RunType and // RunnableType for a Functor. This is where function // signature adapters are applied. -// There are |ARITY| ForceVoidReturn types. // MakeRunnable<> -- Takes a Functor and returns an object in the Runnable // type class that represents the underlying Functor. // There are |O(1)| MakeRunnable types. @@ -71,7 +68,6 @@ // and for ignoring return values. This is separate from // Invoker to avoid creating multiple version of Invoker<> // which grows at O(n^2) with the arity. -// There are |k*ARITY| InvokeHelper types. // Invoker<> -- Unwraps the curried parameters and executes the Runnable. // There are |(ARITY^2 + ARITY)/2| Invoketypes. // BindState<> -- Stores the curried parameters, and is the main entry point @@ -101,550 +97,64 @@ template <typename Functor> class RunnableAdapter; -// Function: Arity 0. -template <typename R> -class RunnableAdapter<R(*)()> { +// Function. +template <typename R, typename... Args> +class RunnableAdapter<R(*)(Args...)> { public: - typedef R (RunType)(); + typedef R (RunType)(Args...); - explicit RunnableAdapter(R(*function)()) + explicit RunnableAdapter(R(*function)(Args...)) : function_(function) { } - R Run() { - return function_(); + R Run(typename CallbackParamTraits<Args>::ForwardType... args) { + return function_(CallbackForward(args)...); } private: - R (*function_)(); + R (*function_)(Args...); }; -// Method: Arity 0. -template <typename R, typename T> -class RunnableAdapter<R(T::*)()> { +// Method. +template <typename R, typename T, typename... Args> +class RunnableAdapter<R(T::*)(Args...)> { public: - typedef R (RunType)(T*); + typedef R (RunType)(T*, Args...); typedef true_type IsMethod; - explicit RunnableAdapter(R(T::*method)()) + explicit RunnableAdapter(R(T::*method)(Args...)) : method_(method) { } - R Run(T* object) { - return (object->*method_)(); + R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) { + return (object->*method_)(CallbackForward(args)...); } private: - R (T::*method_)(); + R (T::*method_)(Args...); }; -// Const Method: Arity 0. -template <typename R, typename T> -class RunnableAdapter<R(T::*)() const> { +// Const Method. +template <typename R, typename T, typename... Args> +class RunnableAdapter<R(T::*)(Args...) const> { public: - typedef R (RunType)(const T*); + typedef R (RunType)(const T*, Args...); typedef true_type IsMethod; - explicit RunnableAdapter(R(T::*method)() const) + explicit RunnableAdapter(R(T::*method)(Args...) const) : method_(method) { } - R Run(const T* object) { - return (object->*method_)(); + R Run(const T* object, + typename CallbackParamTraits<Args>::ForwardType... args) { + return (object->*method_)(CallbackForward(args)...); } private: - R (T::*method_)() const; + R (T::*method_)(Args...) const; }; -// Function: Arity 1. -template <typename R, typename A1> -class RunnableAdapter<R(*)(A1)> { - public: - typedef R (RunType)(A1); - - explicit RunnableAdapter(R(*function)(A1)) - : function_(function) { - } - - R Run(typename CallbackParamTraits<A1>::ForwardType a1) { - return function_(CallbackForward(a1)); - } - - private: - R (*function_)(A1); -}; - -// Method: Arity 1. -template <typename R, typename T, typename A1> -class RunnableAdapter<R(T::*)(A1)> { - public: - typedef R (RunType)(T*, A1); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1) { - return (object->*method_)(CallbackForward(a1)); - } - - private: - R (T::*method_)(A1); -}; - -// Const Method: Arity 1. -template <typename R, typename T, typename A1> -class RunnableAdapter<R(T::*)(A1) const> { - public: - typedef R (RunType)(const T*, A1); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1) { - return (object->*method_)(CallbackForward(a1)); - } - - private: - R (T::*method_)(A1) const; -}; - -// Function: Arity 2. -template <typename R, typename A1, typename A2> -class RunnableAdapter<R(*)(A1, A2)> { - public: - typedef R (RunType)(A1, A2); - - explicit RunnableAdapter(R(*function)(A1, A2)) - : function_(function) { - } - - R Run(typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2) { - return function_(CallbackForward(a1), CallbackForward(a2)); - } - - private: - R (*function_)(A1, A2); -}; - -// Method: Arity 2. -template <typename R, typename T, typename A1, typename A2> -class RunnableAdapter<R(T::*)(A1, A2)> { - public: - typedef R (RunType)(T*, A1, A2); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2)); - } - - private: - R (T::*method_)(A1, A2); -}; - -// Const Method: Arity 2. -template <typename R, typename T, typename A1, typename A2> -class RunnableAdapter<R(T::*)(A1, A2) const> { - public: - typedef R (RunType)(const T*, A1, A2); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2)); - } - - private: - R (T::*method_)(A1, A2) const; -}; - -// Function: Arity 3. -template <typename R, typename A1, typename A2, typename A3> -class RunnableAdapter<R(*)(A1, A2, A3)> { - public: - typedef R (RunType)(A1, A2, A3); - - explicit RunnableAdapter(R(*function)(A1, A2, A3)) - : function_(function) { - } - - R Run(typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3)); - } - - private: - R (*function_)(A1, A2, A3); -}; - -// Method: Arity 3. -template <typename R, typename T, typename A1, typename A2, typename A3> -class RunnableAdapter<R(T::*)(A1, A2, A3)> { - public: - typedef R (RunType)(T*, A1, A2, A3); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3)); - } - - private: - R (T::*method_)(A1, A2, A3); -}; - -// Const Method: Arity 3. -template <typename R, typename T, typename A1, typename A2, typename A3> -class RunnableAdapter<R(T::*)(A1, A2, A3) const> { - public: - typedef R (RunType)(const T*, A1, A2, A3); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3)); - } - - private: - R (T::*method_)(A1, A2, A3) const; -}; - -// Function: Arity 4. -template <typename R, typename A1, typename A2, typename A3, typename A4> -class RunnableAdapter<R(*)(A1, A2, A3, A4)> { - public: - typedef R (RunType)(A1, A2, A3, A4); - - explicit RunnableAdapter(R(*function)(A1, A2, A3, A4)) - : function_(function) { - } - - R Run(typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4)); - } - - private: - R (*function_)(A1, A2, A3, A4); -}; - -// Method: Arity 4. -template <typename R, typename T, typename A1, typename A2, typename A3, - typename A4> -class RunnableAdapter<R(T::*)(A1, A2, A3, A4)> { - public: - typedef R (RunType)(T*, A1, A2, A3, A4); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4)); - } - - private: - R (T::*method_)(A1, A2, A3, A4); -}; - -// Const Method: Arity 4. -template <typename R, typename T, typename A1, typename A2, typename A3, - typename A4> -class RunnableAdapter<R(T::*)(A1, A2, A3, A4) const> { - public: - typedef R (RunType)(const T*, A1, A2, A3, A4); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4)); - } - - private: - R (T::*method_)(A1, A2, A3, A4) const; -}; - -// Function: Arity 5. -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5> -class RunnableAdapter<R(*)(A1, A2, A3, A4, A5)> { - public: - typedef R (RunType)(A1, A2, A3, A4, A5); - - explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5)) - : function_(function) { - } - - R Run(typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5)); - } - - private: - R (*function_)(A1, A2, A3, A4, A5); -}; - -// Method: Arity 5. -template <typename R, typename T, typename A1, typename A2, typename A3, - typename A4, typename A5> -class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5)> { - public: - typedef R (RunType)(T*, A1, A2, A3, A4, A5); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5); -}; - -// Const Method: Arity 5. -template <typename R, typename T, typename A1, typename A2, typename A3, - typename A4, typename A5> -class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5) const> { - public: - typedef R (RunType)(const T*, A1, A2, A3, A4, A5); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5) const; -}; - -// Function: Arity 6. -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6> -class RunnableAdapter<R(*)(A1, A2, A3, A4, A5, A6)> { - public: - typedef R (RunType)(A1, A2, A3, A4, A5, A6); - - explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5, A6)) - : function_(function) { - } - - R Run(typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5, - typename CallbackParamTraits<A6>::ForwardType a6) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6)); - } - - private: - R (*function_)(A1, A2, A3, A4, A5, A6); -}; - -// Method: Arity 6. -template <typename R, typename T, typename A1, typename A2, typename A3, - typename A4, typename A5, typename A6> -class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6)> { - public: - typedef R (RunType)(T*, A1, A2, A3, A4, A5, A6); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5, - typename CallbackParamTraits<A6>::ForwardType a6) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5, A6); -}; - -// Const Method: Arity 6. -template <typename R, typename T, typename A1, typename A2, typename A3, - typename A4, typename A5, typename A6> -class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6) const> { - public: - typedef R (RunType)(const T*, A1, A2, A3, A4, A5, A6); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5, - typename CallbackParamTraits<A6>::ForwardType a6) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5, A6) const; -}; - -// Function: Arity 7. -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6, typename A7> -class RunnableAdapter<R(*)(A1, A2, A3, A4, A5, A6, A7)> { - public: - typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7); - - explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5, A6, A7)) - : function_(function) { - } - - R Run(typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5, - typename CallbackParamTraits<A6>::ForwardType a6, - typename CallbackParamTraits<A7>::ForwardType a7) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6), CallbackForward(a7)); - } - - private: - R (*function_)(A1, A2, A3, A4, A5, A6, A7); -}; - -// Method: Arity 7. -template <typename R, typename T, typename A1, typename A2, typename A3, - typename A4, typename A5, typename A6, typename A7> -class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6, A7)> { - public: - typedef R (RunType)(T*, A1, A2, A3, A4, A5, A6, A7); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6, A7)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5, - typename CallbackParamTraits<A6>::ForwardType a6, - typename CallbackParamTraits<A7>::ForwardType a7) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6), CallbackForward(a7)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5, A6, A7); -}; - -// Const Method: Arity 7. -template <typename R, typename T, typename A1, typename A2, typename A3, - typename A4, typename A5, typename A6, typename A7> -class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6, A7) const> { - public: - typedef R (RunType)(const T*, A1, A2, A3, A4, A5, A6, A7); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6, A7) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1, - typename CallbackParamTraits<A2>::ForwardType a2, - typename CallbackParamTraits<A3>::ForwardType a3, - typename CallbackParamTraits<A4>::ForwardType a4, - typename CallbackParamTraits<A5>::ForwardType a5, - typename CallbackParamTraits<A6>::ForwardType a6, - typename CallbackParamTraits<A7>::ForwardType a7) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6), CallbackForward(a7)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5, A6, A7) const; -}; - - +// TODO(tzik): Remove FunctionTraits after we finish removing bind.pump. // FunctionTraits<> // // Breaks a function signature apart into typedefs for easier introspection. @@ -729,47 +239,9 @@ template <typename Sig> struct ForceVoidReturn; -template <typename R> -struct ForceVoidReturn<R()> { - typedef void(RunType)(); -}; - -template <typename R, typename A1> -struct ForceVoidReturn<R(A1)> { - typedef void(RunType)(A1); -}; - -template <typename R, typename A1, typename A2> -struct ForceVoidReturn<R(A1, A2)> { - typedef void(RunType)(A1, A2); -}; - -template <typename R, typename A1, typename A2, typename A3> -struct ForceVoidReturn<R(A1, A2, A3)> { - typedef void(RunType)(A1, A2, A3); -}; - -template <typename R, typename A1, typename A2, typename A3, typename A4> -struct ForceVoidReturn<R(A1, A2, A3, A4)> { - typedef void(RunType)(A1, A2, A3, A4); -}; - -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5> -struct ForceVoidReturn<R(A1, A2, A3, A4, A5)> { - typedef void(RunType)(A1, A2, A3, A4, A5); -}; - -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6> -struct ForceVoidReturn<R(A1, A2, A3, A4, A5, A6)> { - typedef void(RunType)(A1, A2, A3, A4, A5, A6); -}; - -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6, typename A7> -struct ForceVoidReturn<R(A1, A2, A3, A4, A5, A6, A7)> { - typedef void(RunType)(A1, A2, A3, A4, A5, A6, A7); +template <typename R, typename... Args> +struct ForceVoidReturn<R(Args...)> { + typedef void(RunType)(Args...); }; @@ -840,246 +312,28 @@ typename ArgsType> struct InvokeHelper; -template <typename ReturnType, typename Runnable> +template <typename ReturnType, typename Runnable, typename... Args> struct InvokeHelper<false, ReturnType, Runnable, - void()> { - static ReturnType MakeItSo(Runnable runnable) { - return runnable.Run(); + void(Args...)> { + static ReturnType MakeItSo(Runnable runnable, Args... args) { + return runnable.Run(CallbackForward(args)...); } }; -template <typename Runnable> -struct InvokeHelper<false, void, Runnable, - void()> { - static void MakeItSo(Runnable runnable) { - runnable.Run(); +template <typename Runnable, typename... Args> +struct InvokeHelper<false, void, Runnable, void(Args...)> { + static void MakeItSo(Runnable runnable, Args... args) { + runnable.Run(CallbackForward(args)...); } }; -template <typename ReturnType, typename Runnable,typename A1> -struct InvokeHelper<false, ReturnType, Runnable, - void(A1)> { - static ReturnType MakeItSo(Runnable runnable, A1 a1) { - return runnable.Run(CallbackForward(a1)); - } -}; - -template <typename Runnable,typename A1> -struct InvokeHelper<false, void, Runnable, - void(A1)> { - static void MakeItSo(Runnable runnable, A1 a1) { - runnable.Run(CallbackForward(a1)); - } -}; - -template <typename Runnable, typename BoundWeakPtr> -struct InvokeHelper<true, void, Runnable, - void(BoundWeakPtr)> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr) { +template <typename Runnable, typename BoundWeakPtr, typename... Args> +struct InvokeHelper<true, void, Runnable, void(BoundWeakPtr, Args...)> { + static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) { if (!weak_ptr.get()) { return; } - runnable.Run(weak_ptr.get()); - } -}; - -template <typename ReturnType, typename Runnable,typename A1, typename A2> -struct InvokeHelper<false, ReturnType, Runnable, - void(A1, A2)> { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2)); - } -}; - -template <typename Runnable,typename A1, typename A2> -struct InvokeHelper<false, void, Runnable, - void(A1, A2)> { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2) { - runnable.Run(CallbackForward(a1), CallbackForward(a2)); - } -}; - -template <typename Runnable, typename BoundWeakPtr, typename A2> -struct InvokeHelper<true, void, Runnable, - void(BoundWeakPtr, A2)> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2)); - } -}; - -template <typename ReturnType, typename Runnable,typename A1, typename A2, - typename A3> -struct InvokeHelper<false, ReturnType, Runnable, - void(A1, A2, A3)> { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3)); - } -}; - -template <typename Runnable,typename A1, typename A2, typename A3> -struct InvokeHelper<false, void, Runnable, - void(A1, A2, A3)> { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3)); - } -}; - -template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3> -struct InvokeHelper<true, void, Runnable, - void(BoundWeakPtr, A2, A3)> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3)); - } -}; - -template <typename ReturnType, typename Runnable,typename A1, typename A2, - typename A3, typename A4> -struct InvokeHelper<false, ReturnType, Runnable, - void(A1, A2, A3, A4)> { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4)); - } -}; - -template <typename Runnable,typename A1, typename A2, typename A3, typename A4> -struct InvokeHelper<false, void, Runnable, - void(A1, A2, A3, A4)> { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4)); - } -}; - -template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3, - typename A4> -struct InvokeHelper<true, void, Runnable, - void(BoundWeakPtr, A2, A3, A4)> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3, - A4 a4) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4)); - } -}; - -template <typename ReturnType, typename Runnable,typename A1, typename A2, - typename A3, typename A4, typename A5> -struct InvokeHelper<false, ReturnType, Runnable, - void(A1, A2, A3, A4, A5)> { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, - A5 a5) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5)); - } -}; - -template <typename Runnable,typename A1, typename A2, typename A3, typename A4, - typename A5> -struct InvokeHelper<false, void, Runnable, - void(A1, A2, A3, A4, A5)> { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5)); - } -}; - -template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3, - typename A4, typename A5> -struct InvokeHelper<true, void, Runnable, - void(BoundWeakPtr, A2, A3, A4, A5)> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3, - A4 a4, A5 a5) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5)); - } -}; - -template <typename ReturnType, typename Runnable,typename A1, typename A2, - typename A3, typename A4, typename A5, typename A6> -struct InvokeHelper<false, ReturnType, Runnable, - void(A1, A2, A3, A4, A5, A6)> { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, - A5 a5, A6 a6) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6)); - } -}; - -template <typename Runnable,typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6> -struct InvokeHelper<false, void, Runnable, - void(A1, A2, A3, A4, A5, A6)> { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, - A6 a6) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5), CallbackForward(a6)); - } -}; - -template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3, - typename A4, typename A5, typename A6> -struct InvokeHelper<true, void, Runnable, - void(BoundWeakPtr, A2, A3, A4, A5, A6)> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3, - A4 a4, A5 a5, A6 a6) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5), CallbackForward(a6)); - } -}; - -template <typename ReturnType, typename Runnable,typename A1, typename A2, - typename A3, typename A4, typename A5, typename A6, typename A7> -struct InvokeHelper<false, ReturnType, Runnable, - void(A1, A2, A3, A4, A5, A6, A7)> { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, - A5 a5, A6 a6, A7 a7) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6), CallbackForward(a7)); - } -}; - -template <typename Runnable,typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6, typename A7> -struct InvokeHelper<false, void, Runnable, - void(A1, A2, A3, A4, A5, A6, A7)> { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, - A6 a6, A7 a7) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5), CallbackForward(a6), - CallbackForward(a7)); - } -}; - -template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3, - typename A4, typename A5, typename A6, typename A7> -struct InvokeHelper<true, void, Runnable, - void(BoundWeakPtr, A2, A3, A4, A5, A6, A7)> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3, - A4 a4, A5 a5, A6 a6, A7 a7) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5), CallbackForward(a6), - CallbackForward(a7)); + runnable.Run(weak_ptr.get(), CallbackForward(args)...); } };
diff --git a/base/bind_internal.h.pump b/base/bind_internal.h.pump index f632b99..9ddca47 100644 --- a/base/bind_internal.h.pump +++ b/base/bind_internal.h.pump
@@ -57,18 +57,15 @@ // Types: // RunnableAdapter<> -- Wraps the various "function" pointer types into an // object that adheres to the Runnable interface. -// There are |3*ARITY| RunnableAdapter types. // FunctionTraits<> -- Type traits that unwrap a function signature into a // a set of easier to use typedefs. Used mainly for // compile time asserts. // There are |ARITY| FunctionTraits types. // ForceVoidReturn<> -- Helper class for translating function signatures to // equivalent forms with a "void" return type. -// There are |ARITY| ForceVoidReturn types. // FunctorTraits<> -- Type traits used determine the correct RunType and // RunnableType for a Functor. This is where function // signature adapters are applied. -// There are |ARITY| ForceVoidReturn types. // MakeRunnable<> -- Takes a Functor and returns an object in the Runnable // type class that represents the underlying Functor. // There are |O(1)| MakeRunnable types. @@ -77,7 +74,6 @@ // and for ignoring return values. This is separate from // Invoker to avoid creating multiple version of Invoker<> // which grows at O(n^2) with the arity. -// There are |k*ARITY| InvokeHelper types. // Invoker<> -- Unwraps the curried parameters and executes the Runnable. // There are |(ARITY^2 + ARITY)/2| Invoketypes. // BindState<> -- Stores the curried parameters, and is the main entry point @@ -107,75 +103,64 @@ template <typename Functor> class RunnableAdapter; -$for ARITY [[ -$range ARG 1..ARITY - -// Function: Arity $(ARITY). -template <typename R[[]] -$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> -class RunnableAdapter<R(*)($for ARG , [[A$(ARG)]])> { +// Function. +template <typename R, typename... Args> +class RunnableAdapter<R(*)(Args...)> { public: - typedef R (RunType)($for ARG , [[A$(ARG)]]); + typedef R (RunType)(Args...); - explicit RunnableAdapter(R(*function)($for ARG , [[A$(ARG)]])) + explicit RunnableAdapter(R(*function)(Args...)) : function_(function) { } - R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { - return function_($for ARG , [[CallbackForward(a$(ARG))]]); + R Run(typename CallbackParamTraits<Args>::ForwardType... args) { + return function_(CallbackForward(args)...); } private: - R (*function_)($for ARG , [[A$(ARG)]]); + R (*function_)(Args...); }; -// Method: Arity $(ARITY). -template <typename R, typename T[[]] -$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> -class RunnableAdapter<R(T::*)($for ARG , [[A$(ARG)]])> { +// Method. +template <typename R, typename T, typename... Args> +class RunnableAdapter<R(T::*)(Args...)> { public: - typedef R (RunType)(T*[[]] -$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]); + typedef R (RunType)(T*, Args...); typedef true_type IsMethod; - explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]])) + explicit RunnableAdapter(R(T::*method)(Args...)) : method_(method) { } - R Run(T* object[[]] -$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { - return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]); + R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) { + return (object->*method_)(CallbackForward(args)...); } private: - R (T::*method_)($for ARG , [[A$(ARG)]]); + R (T::*method_)(Args...); }; -// Const Method: Arity $(ARITY). -template <typename R, typename T[[]] -$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> -class RunnableAdapter<R(T::*)($for ARG , [[A$(ARG)]]) const> { +// Const Method. +template <typename R, typename T, typename... Args> +class RunnableAdapter<R(T::*)(Args...) const> { public: - typedef R (RunType)(const T*[[]] -$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]); + typedef R (RunType)(const T*, Args...); typedef true_type IsMethod; - explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]]) const) + explicit RunnableAdapter(R(T::*method)(Args...) const) : method_(method) { } - R Run(const T* object[[]] -$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { - return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]); + R Run(const T* object, + typename CallbackParamTraits<Args>::ForwardType... args) { + return (object->*method_)(CallbackForward(args)...); } private: - R (T::*method_)($for ARG , [[A$(ARG)]]) const; + R (T::*method_)(Args...) const; }; -]] $$ for ARITY - - +// TODO(tzik): Remove FunctionTraits after we finish removing bind.pump. // FunctionTraits<> // // Breaks a function signature apart into typedefs for easier introspection. @@ -205,17 +190,11 @@ template <typename Sig> struct ForceVoidReturn; -$for ARITY [[ -$range ARG 1..ARITY - -template <typename R[[]] -$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> -struct ForceVoidReturn<R($for ARG , [[A$(ARG)]])> { - typedef void(RunType)($for ARG , [[A$(ARG)]]); +template <typename R, typename... Args> +struct ForceVoidReturn<R(Args...)> { + typedef void(RunType)(Args...); }; -]] $$ for ARITY - // FunctorTraits<> // @@ -284,51 +263,31 @@ typename ArgsType> struct InvokeHelper; -$for ARITY [[ -$range ARG 1..ARITY -$range WEAKCALL_ARG 2..ARITY - -template <typename ReturnType, typename Runnable[[]] -$if ARITY > 0 [[,]] $for ARG , [[typename A$(ARG)]]> +template <typename ReturnType, typename Runnable, typename... Args> struct InvokeHelper<false, ReturnType, Runnable, - void($for ARG , [[A$(ARG)]])> { - static ReturnType MakeItSo(Runnable runnable[[]] -$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { - return runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]); + void(Args...)> { + static ReturnType MakeItSo(Runnable runnable, Args... args) { + return runnable.Run(CallbackForward(args)...); } }; -template <typename Runnable[[]] -$if ARITY > 0 [[,]] $for ARG , [[typename A$(ARG)]]> -struct InvokeHelper<false, void, Runnable, - void($for ARG , [[A$(ARG)]])> { - static void MakeItSo(Runnable runnable[[]] -$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { - runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]); +template <typename Runnable, typename... Args> +struct InvokeHelper<false, void, Runnable, void(Args...)> { + static void MakeItSo(Runnable runnable, Args... args) { + runnable.Run(CallbackForward(args)...); } }; -$if ARITY > 0 [[ - -template <typename Runnable[[]], typename BoundWeakPtr -$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[typename A$(WEAKCALL_ARG)]]> -struct InvokeHelper<true, void, Runnable, - void(BoundWeakPtr -$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[A$(WEAKCALL_ARG)]])> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr -$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[A$(WEAKCALL_ARG) a$(WEAKCALL_ARG)]]) { +template <typename Runnable, typename BoundWeakPtr, typename... Args> +struct InvokeHelper<true, void, Runnable, void(BoundWeakPtr, Args...)> { + static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) { if (!weak_ptr.get()) { return; } - runnable.Run(weak_ptr.get() -$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[CallbackForward(a$(WEAKCALL_ARG))]]); + runnable.Run(weak_ptr.get(), CallbackForward(args)...); } }; -]] - -]] $$ for ARITY - #if !defined(_MSC_VER) template <typename ReturnType, typename Runnable, typename ArgsType>
diff --git a/base/callback.h b/base/callback.h index 364f506..00669dd 100644 --- a/base/callback.h +++ b/base/callback.h
@@ -1,8 +1,3 @@ -// This file was GENERATED by command: -// pump.py callback.h.pump -// DO NOT EDIT BY HAND!!! - - // Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -367,10 +362,10 @@ struct BindState; } // namespace internal -template <typename R> -class Callback<R(void)> : public internal::CallbackBase { +template <typename R, typename... Args> +class Callback<R(Args...)> : public internal::CallbackBase { public: - typedef R(RunType)(); + typedef R(RunType)(Args...); Callback() : CallbackBase(NULL) { } @@ -380,7 +375,6 @@ Callback(internal::BindState<Runnable, BindRunType, BoundArgsType>* bind_state) : CallbackBase(bind_state) { - // Force the assignment to a local variable of PolymorphicInvoke // so the compiler will typecheck that the passed in Run() method has // the correct type. @@ -394,377 +388,24 @@ return CallbackBase::Equals(other); } - R Run() const { + R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args) + const { PolymorphicInvoke f = reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - return f(bind_state_.get()); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*); - -}; - -template <typename R, typename A1> -class Callback<R(A1)> : public internal::CallbackBase { - public: - typedef R(RunType)(A1); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template <typename Runnable, typename BindRunType, typename BoundArgsType> - Callback(internal::BindState<Runnable, BindRunType, - BoundArgsType>* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgsType> - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1) const { - PolymorphicInvoke f = - reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1)); + return f(bind_state_.get(), internal::CallbackForward(args)...); } private: typedef R(*PolymorphicInvoke)( internal::BindStateBase*, - typename internal::CallbackParamTraits<A1>::ForwardType); - + typename internal::CallbackParamTraits<Args>::ForwardType...); }; -template <typename R, typename A1, typename A2> -class Callback<R(A1, A2)> : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template <typename Runnable, typename BindRunType, typename BoundArgsType> - Callback(internal::BindState<Runnable, BindRunType, - BoundArgsType>* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgsType> - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2) const { - PolymorphicInvoke f = - reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits<A1>::ForwardType, - typename internal::CallbackParamTraits<A2>::ForwardType); - -}; - -template <typename R, typename A1, typename A2, typename A3> -class Callback<R(A1, A2, A3)> : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template <typename Runnable, typename BindRunType, typename BoundArgsType> - Callback(internal::BindState<Runnable, BindRunType, - BoundArgsType>* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgsType> - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3) const { - PolymorphicInvoke f = - reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits<A1>::ForwardType, - typename internal::CallbackParamTraits<A2>::ForwardType, - typename internal::CallbackParamTraits<A3>::ForwardType); - -}; - -template <typename R, typename A1, typename A2, typename A3, typename A4> -class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3, A4); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template <typename Runnable, typename BindRunType, typename BoundArgsType> - Callback(internal::BindState<Runnable, BindRunType, - BoundArgsType>* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgsType> - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3, - typename internal::CallbackParamTraits<A4>::ForwardType a4) const { - PolymorphicInvoke f = - reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3), - internal::CallbackForward(a4)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits<A1>::ForwardType, - typename internal::CallbackParamTraits<A2>::ForwardType, - typename internal::CallbackParamTraits<A3>::ForwardType, - typename internal::CallbackParamTraits<A4>::ForwardType); - -}; - -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5> -class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3, A4, A5); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template <typename Runnable, typename BindRunType, typename BoundArgsType> - Callback(internal::BindState<Runnable, BindRunType, - BoundArgsType>* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgsType> - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3, - typename internal::CallbackParamTraits<A4>::ForwardType a4, - typename internal::CallbackParamTraits<A5>::ForwardType a5) const { - PolymorphicInvoke f = - reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3), - internal::CallbackForward(a4), - internal::CallbackForward(a5)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits<A1>::ForwardType, - typename internal::CallbackParamTraits<A2>::ForwardType, - typename internal::CallbackParamTraits<A3>::ForwardType, - typename internal::CallbackParamTraits<A4>::ForwardType, - typename internal::CallbackParamTraits<A5>::ForwardType); - -}; - -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6> -class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3, A4, A5, A6); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template <typename Runnable, typename BindRunType, typename BoundArgsType> - Callback(internal::BindState<Runnable, BindRunType, - BoundArgsType>* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgsType> - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3, - typename internal::CallbackParamTraits<A4>::ForwardType a4, - typename internal::CallbackParamTraits<A5>::ForwardType a5, - typename internal::CallbackParamTraits<A6>::ForwardType a6) const { - PolymorphicInvoke f = - reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3), - internal::CallbackForward(a4), - internal::CallbackForward(a5), - internal::CallbackForward(a6)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits<A1>::ForwardType, - typename internal::CallbackParamTraits<A2>::ForwardType, - typename internal::CallbackParamTraits<A3>::ForwardType, - typename internal::CallbackParamTraits<A4>::ForwardType, - typename internal::CallbackParamTraits<A5>::ForwardType, - typename internal::CallbackParamTraits<A6>::ForwardType); - -}; - -template <typename R, typename A1, typename A2, typename A3, typename A4, - typename A5, typename A6, typename A7> -class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3, A4, A5, A6, A7); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template <typename Runnable, typename BindRunType, typename BoundArgsType> - Callback(internal::BindState<Runnable, BindRunType, - BoundArgsType>* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgsType> - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3, - typename internal::CallbackParamTraits<A4>::ForwardType a4, - typename internal::CallbackParamTraits<A5>::ForwardType a5, - typename internal::CallbackParamTraits<A6>::ForwardType a6, - typename internal::CallbackParamTraits<A7>::ForwardType a7) const { - PolymorphicInvoke f = - reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3), - internal::CallbackForward(a4), - internal::CallbackForward(a5), - internal::CallbackForward(a6), - internal::CallbackForward(a7)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits<A1>::ForwardType, - typename internal::CallbackParamTraits<A2>::ForwardType, - typename internal::CallbackParamTraits<A3>::ForwardType, - typename internal::CallbackParamTraits<A4>::ForwardType, - typename internal::CallbackParamTraits<A5>::ForwardType, - typename internal::CallbackParamTraits<A6>::ForwardType, - typename internal::CallbackParamTraits<A7>::ForwardType); - -}; - - // Syntactic sugar to make Callback<void(void)> easier to declare since it // will be used in a lot of APIs with delayed execution. typedef Callback<void(void)> Closure; } // namespace base -#endif // BASE_CALLBACK_H +#endif // BASE_CALLBACK_H_
diff --git a/base/callback.h.pump b/base/callback.h.pump deleted file mode 100644 index 686196d..0000000 --- a/base/callback.h.pump +++ /dev/null
@@ -1,436 +0,0 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ - -$$ See comment for MAX_ARITY in base/bind.h.pump. -$var MAX_ARITY = 7 - -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CALLBACK_H_ -#define BASE_CALLBACK_H_ - -#include "base/callback_forward.h" -#include "base/callback_internal.h" -#include "base/template_util.h" - -// NOTE: Header files that do not require the full definition of Callback or -// Closure should #include "base/callback_forward.h" instead of this file. - -// ----------------------------------------------------------------------------- -// Introduction -// ----------------------------------------------------------------------------- -// -// The templated Callback class is a generalized function object. Together -// with the Bind() function in bind.h, they provide a type-safe method for -// performing partial application of functions. -// -// Partial application (or "currying") is the process of binding a subset of -// a function's arguments to produce another function that takes fewer -// arguments. This can be used to pass around a unit of delayed execution, -// much like lexical closures are used in other languages. For example, it -// is used in Chromium code to schedule tasks on different MessageLoops. -// -// A callback with no unbound input parameters (base::Callback<void(void)>) -// is called a base::Closure. Note that this is NOT the same as what other -// languages refer to as a closure -- it does not retain a reference to its -// enclosing environment. -// -// MEMORY MANAGEMENT AND PASSING -// -// The Callback objects themselves should be passed by const-reference, and -// stored by copy. They internally store their state via a refcounted class -// and thus do not need to be deleted. -// -// The reason to pass via a const-reference is to avoid unnecessary -// AddRef/Release pairs to the internal state. -// -// -// ----------------------------------------------------------------------------- -// Quick reference for basic stuff -// ----------------------------------------------------------------------------- -// -// BINDING A BARE FUNCTION -// -// int Return5() { return 5; } -// base::Callback<int(void)> func_cb = base::Bind(&Return5); -// LOG(INFO) << func_cb.Run(); // Prints 5. -// -// BINDING A CLASS METHOD -// -// The first argument to bind is the member function to call, the second is -// the object on which to call it. -// -// class Ref : public base::RefCountedThreadSafe<Ref> { -// public: -// int Foo() { return 3; } -// void PrintBye() { LOG(INFO) << "bye."; } -// }; -// scoped_refptr<Ref> ref = new Ref(); -// base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref); -// LOG(INFO) << ref_cb.Run(); // Prints out 3. -// -// By default the object must support RefCounted or you will get a compiler -// error. If you're passing between threads, be sure it's -// RefCountedThreadSafe! See "Advanced binding of member functions" below if -// you don't want to use reference counting. -// -// RUNNING A CALLBACK -// -// Callbacks can be run with their "Run" method, which has the same -// signature as the template argument to the callback. -// -// void DoSomething(const base::Callback<void(int, std::string)>& callback) { -// callback.Run(5, "hello"); -// } -// -// Callbacks can be run more than once (they don't get deleted or marked when -// run). However, this precludes using base::Passed (see below). -// -// void DoSomething(const base::Callback<double(double)>& callback) { -// double myresult = callback.Run(3.14159); -// myresult += callback.Run(2.71828); -// } -// -// PASSING UNBOUND INPUT PARAMETERS -// -// Unbound parameters are specified at the time a callback is Run(). They are -// specified in the Callback template type: -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc); -// cb.Run(23, "hello, world"); -// -// PASSING BOUND INPUT PARAMETERS -// -// Bound parameters are specified when you create thee callback as arguments -// to Bind(). They will be passed to the function and the Run()ner of the -// callback doesn't see those values or even know that the function it's -// calling. -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world"); -// cb.Run(); -// -// A callback with no unbound input parameters (base::Callback<void(void)>) -// is called a base::Closure. So we could have also written: -// -// base::Closure cb = base::Bind(&MyFunc, 23, "hello world"); -// -// When calling member functions, bound parameters just go after the object -// pointer. -// -// base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world"); -// -// PARTIAL BINDING OF PARAMETERS -// -// You can specify some parameters when you create the callback, and specify -// the rest when you execute the callback. -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23); -// cb.Run("hello world"); -// -// When calling a function bound parameters are first, followed by unbound -// parameters. -// -// -// ----------------------------------------------------------------------------- -// Quick reference for advanced binding -// ----------------------------------------------------------------------------- -// -// BINDING A CLASS METHOD WITH WEAK POINTERS -// -// base::Bind(&MyClass::Foo, GetWeakPtr()); -// -// The callback will not be run if the object has already been destroyed. -// DANGER: weak pointers are not threadsafe, so don't use this -// when passing between threads! -// -// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT -// -// base::Bind(&MyClass::Foo, base::Unretained(this)); -// -// This disables all lifetime management on the object. You're responsible -// for making sure the object is alive at the time of the call. You break it, -// you own it! -// -// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS -// -// MyClass* myclass = new MyClass; -// base::Bind(&MyClass::Foo, base::Owned(myclass)); -// -// The object will be deleted when the callback is destroyed, even if it's -// not run (like if you post a task during shutdown). Potentially useful for -// "fire and forget" cases. -// -// IGNORING RETURN VALUES -// -// Sometimes you want to call a function that returns a value in a callback -// that doesn't expect a return value. -// -// int DoSomething(int arg) { cout << arg << endl; } -// base::Callback<void<int>) cb = -// base::Bind(base::IgnoreResult(&DoSomething)); -// -// -// ----------------------------------------------------------------------------- -// Quick reference for binding parameters to Bind() -// ----------------------------------------------------------------------------- -// -// Bound parameters are specified as arguments to Bind() and are passed to the -// function. A callback with no parameters or no unbound parameters is called a -// Closure (base::Callback<void(void)> and base::Closure are the same thing). -// -// PASSING PARAMETERS OWNED BY THE CALLBACK -// -// void Foo(int* arg) { cout << *arg << endl; } -// int* pn = new int(1); -// base::Closure foo_callback = base::Bind(&foo, base::Owned(pn)); -// -// The parameter will be deleted when the callback is destroyed, even if it's -// not run (like if you post a task during shutdown). -// -// PASSING PARAMETERS AS A scoped_ptr -// -// void TakesOwnership(scoped_ptr<Foo> arg) {} -// scoped_ptr<Foo> f(new Foo); -// // f becomes null during the following call. -// base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f)); -// -// Ownership of the parameter will be with the callback until the it is run, -// when ownership is passed to the callback function. This means the callback -// can only be run once. If the callback is never run, it will delete the -// object when it's destroyed. -// -// PASSING PARAMETERS AS A scoped_refptr -// -// void TakesOneRef(scoped_refptr<Foo> arg) {} -// scoped_refptr<Foo> f(new Foo) -// base::Closure cb = base::Bind(&TakesOneRef, f); -// -// This should "just work." The closure will take a reference as long as it -// is alive, and another reference will be taken for the called function. -// -// PASSING PARAMETERS BY REFERENCE -// -// void foo(int arg) { cout << arg << endl } -// int n = 1; -// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n)); -// n = 2; -// has_ref.Run(); // Prints "2" -// -// Normally parameters are copied in the closure. DANGER: ConstRef stores a -// const reference instead, referencing the original parameter. This means -// that you must ensure the object outlives the callback! -// -// -// ----------------------------------------------------------------------------- -// Implementation notes -// ----------------------------------------------------------------------------- -// -// WHERE IS THIS DESIGN FROM: -// -// The design Callback and Bind is heavily influenced by C++'s -// tr1::function/tr1::bind, and by the "Google Callback" system used inside -// Google. -// -// -// HOW THE IMPLEMENTATION WORKS: -// -// There are three main components to the system: -// 1) The Callback classes. -// 2) The Bind() functions. -// 3) The arguments wrappers (e.g., Unretained() and ConstRef()). -// -// The Callback classes represent a generic function pointer. Internally, -// it stores a refcounted piece of state that represents the target function -// and all its bound parameters. Each Callback specialization has a templated -// constructor that takes an BindState<>*. In the context of the constructor, -// the static type of this BindState<> pointer uniquely identifies the -// function it is representing, all its bound parameters, and a Run() method -// that is capable of invoking the target. -// -// Callback's constructor takes the BindState<>* that has the full static type -// and erases the target function type as well as the types of the bound -// parameters. It does this by storing a pointer to the specific Run() -// function, and upcasting the state of BindState<>* to a -// BindStateBase*. This is safe as long as this BindStateBase pointer -// is only used with the stored Run() pointer. -// -// To BindState<> objects are created inside the Bind() functions. -// These functions, along with a set of internal templates, are responsible for -// -// - Unwrapping the function signature into return type, and parameters -// - Determining the number of parameters that are bound -// - Creating the BindState storing the bound parameters -// - Performing compile-time asserts to avoid error-prone behavior -// - Returning an Callback<> with an arity matching the number of unbound -// parameters and that knows the correct refcounting semantics for the -// target object if we are binding a method. -// -// The Bind functions do the above using type-inference, and template -// specializations. -// -// By default Bind() will store copies of all bound parameters, and attempt -// to refcount a target object if the function being bound is a class method. -// These copies are created even if the function takes parameters as const -// references. (Binding to non-const references is forbidden, see bind.h.) -// -// To change this behavior, we introduce a set of argument wrappers -// (e.g., Unretained(), and ConstRef()). These are simple container templates -// that are passed by value, and wrap a pointer to argument. See the -// file-level comment in base/bind_helpers.h for more info. -// -// These types are passed to the Unwrap() functions, and the MaybeRefcount() -// functions respectively to modify the behavior of Bind(). The Unwrap() -// and MaybeRefcount() functions change behavior by doing partial -// specialization based on whether or not a parameter is a wrapper type. -// -// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium. -// -// -// WHY NOT TR1 FUNCTION/BIND? -// -// Direct use of tr1::function and tr1::bind was considered, but ultimately -// rejected because of the number of copy constructors invocations involved -// in the binding of arguments during construction, and the forwarding of -// arguments during invocation. These copies will no longer be an issue in -// C++0x because C++0x will support rvalue reference allowing for the compiler -// to avoid these copies. However, waiting for C++0x is not an option. -// -// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the -// tr1::bind call itself will invoke a non-trivial copy constructor three times -// for each bound parameter. Also, each when passing a tr1::function, each -// bound argument will be copied again. -// -// In addition to the copies taken at binding and invocation, copying a -// tr1::function causes a copy to be made of all the bound parameters and -// state. -// -// Furthermore, in Chromium, it is desirable for the Callback to take a -// reference on a target object when representing a class method call. This -// is not supported by tr1. -// -// Lastly, tr1::function and tr1::bind has a more general and flexible API. -// This includes things like argument reordering by use of -// tr1::bind::placeholder, support for non-const reference parameters, and some -// limited amount of subtyping of the tr1::function object (e.g., -// tr1::function<int(int)> is convertible to tr1::function<void(int)>). -// -// These are not features that are required in Chromium. Some of them, such as -// allowing for reference parameters, and subtyping of functions, may actually -// become a source of errors. Removing support for these features actually -// allows for a simpler implementation, and a terser Currying API. -// -// -// WHY NOT GOOGLE CALLBACKS? -// -// The Google callback system also does not support refcounting. Furthermore, -// its implementation has a number of strange edge cases with respect to type -// conversion of its arguments. In particular, the argument's constness must -// at times match exactly the function signature, or the type-inference might -// break. Given the above, writing a custom solution was easier. -// -// -// MISSING FUNCTIONALITY -// - Invoking the return of Bind. Bind(&foo).Run() does not work; -// - Binding arrays to functions that take a non-const pointer. -// Example: -// void Foo(const char* ptr); -// void Bar(char* ptr); -// Bind(&Foo, "test"); -// Bind(&Bar, "test"); // This fails because ptr is not const. - -namespace base { - -// First, we forward declare the Callback class template. This informs the -// compiler that the template only has 1 type parameter which is the function -// signature that the Callback is representing. -// -// After this, create template specializations for 0-$(MAX_ARITY) parameters. Note that -// even though the template typelist grows, the specialization still -// only has one type: the function signature. -// -// If you are thinking of forward declaring Callback in your own header file, -// please include "base/callback_forward.h" instead. -template <typename Sig> -class Callback; - -namespace internal { -template <typename Runnable, typename RunType, typename BoundArgsType> -struct BindState; -} // namespace internal - - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$range ARG 1..ARITY - -$if ARITY == 0 [[ -template <typename R> -class Callback<R(void)> : public internal::CallbackBase { -]] $else [[ -template <typename R, $for ARG , [[typename A$(ARG)]]> -class Callback<R($for ARG , [[A$(ARG)]])> : public internal::CallbackBase { -]] - - public: - typedef R(RunType)($for ARG , [[A$(ARG)]]); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template <typename Runnable, typename BindRunType, typename BoundArgsType> - Callback(internal::BindState<Runnable, BindRunType, - BoundArgsType>* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgsType> - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run($for ARG , - [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const { - PolymorphicInvoke f = - reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); - - return f(bind_state_.get()[[]] -$if ARITY != 0 [[, ]] -$for ARG , - [[internal::CallbackForward(a$(ARG))]]); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*[[]] -$if ARITY != 0 [[, ]] -$for ARG , [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType]]); - -}; - - -]] $$ for ARITY - -// Syntactic sugar to make Callback<void(void)> easier to declare since it -// will be used in a lot of APIs with delayed execution. -typedef Callback<void(void)> Closure; - -} // namespace base - -#endif // BASE_CALLBACK_H
diff --git a/base/callback_internal.h b/base/callback_internal.h index b85973d..9dca023 100644 --- a/base/callback_internal.h +++ b/base/callback_internal.h
@@ -81,6 +81,28 @@ !is_const<T>::value; }; +// Returns |Then| as SelectType::Type if |condition| is true. Otherwise returns +// |Else|. +template <bool condition, typename Then, typename Else> +struct SelectType { + typedef Then Type; +}; + +template <typename Then, typename Else> +struct SelectType<false, Then, Else> { + typedef Else Type; +}; + +template <typename> +struct CallbackParamTraitsForMoveOnlyType; + +template <typename> +struct CallbackParamTraitsForNonMoveOnlyType; + +// TODO(tzik): Use a default parameter once MSVS supports variadic templates +// with default values. +// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates +// // This is a typetraits object that's used to take an argument type, and // extract a suitable type for storing and forwarding arguments. // @@ -92,8 +114,15 @@ // parameters by const reference. In this case, we end up passing an actual // array type in the initializer list which C++ does not allow. This will // break passing of C-string literals. -template <typename T, bool is_move_only = IsMoveOnlyType<T>::value> -struct CallbackParamTraits { +template <typename T> +struct CallbackParamTraits + : SelectType<IsMoveOnlyType<T>::value, + CallbackParamTraitsForMoveOnlyType<T>, + CallbackParamTraitsForNonMoveOnlyType<T> >::Type { +}; + +template <typename T> +struct CallbackParamTraitsForNonMoveOnlyType { typedef const T& ForwardType; typedef T StorageType; }; @@ -104,7 +133,7 @@ // // The ForwardType should only be used for unbound arguments. template <typename T> -struct CallbackParamTraits<T&, false> { +struct CallbackParamTraitsForNonMoveOnlyType<T&> { typedef T& ForwardType; typedef T StorageType; }; @@ -115,14 +144,14 @@ // T[n]" does not seem to match correctly, so we are stuck with this // restriction. template <typename T, size_t n> -struct CallbackParamTraits<T[n], false> { +struct CallbackParamTraitsForNonMoveOnlyType<T[n]> { typedef const T* ForwardType; typedef const T* StorageType; }; // See comment for CallbackParamTraits<T[n]>. template <typename T> -struct CallbackParamTraits<T[], false> { +struct CallbackParamTraitsForNonMoveOnlyType<T[]> { typedef const T* ForwardType; typedef const T* StorageType; }; @@ -141,7 +170,7 @@ // reference cannot be used with temporaries which means the result of a // function or a cast would not be usable with Callback<> or Bind(). template <typename T> -struct CallbackParamTraits<T, true> { +struct CallbackParamTraitsForMoveOnlyType { typedef T ForwardType; typedef T StorageType; };
diff --git a/base/callback_list.h b/base/callback_list.h index 5b911fd..aeed5f1 100644 --- a/base/callback_list.h +++ b/base/callback_list.h
@@ -1,8 +1,3 @@ -// This file was GENERATED by command: -// pump.py callback_list.h.pump -// DO NOT EDIT BY HAND!!! - - // Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -208,192 +203,21 @@ template <typename Sig> class CallbackList; -template <> -class CallbackList<void(void)> - : public internal::CallbackListBase<Callback<void(void)> > { +template <typename... Args> +class CallbackList<void(Args...)> + : public internal::CallbackListBase<Callback<void(Args...)> > { public: - typedef Callback<void(void)> CallbackType; + typedef Callback<void(Args...)> CallbackType; CallbackList() {} - void Notify() { - internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); - CallbackType* cb; - while ((cb = it.GetNext()) != NULL) { - cb->Run(); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackList); -}; - -template <typename A1> -class CallbackList<void(A1)> - : public internal::CallbackListBase<Callback<void(A1)> > { - public: - typedef Callback<void(A1)> CallbackType; - - CallbackList() {} - - void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1) { + void Notify( + typename internal::CallbackParamTraits<Args>::ForwardType... args) { typename internal::CallbackListBase<CallbackType>::Iterator it = this->GetIterator(); CallbackType* cb; while ((cb = it.GetNext()) != NULL) { - cb->Run(a1); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackList); -}; - -template <typename A1, typename A2> -class CallbackList<void(A1, A2)> - : public internal::CallbackListBase<Callback<void(A1, A2)> > { - public: - typedef Callback<void(A1, A2)> CallbackType; - - CallbackList() {} - - void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2) { - typename internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); - CallbackType* cb; - while ((cb = it.GetNext()) != NULL) { - cb->Run(a1, a2); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackList); -}; - -template <typename A1, typename A2, typename A3> -class CallbackList<void(A1, A2, A3)> - : public internal::CallbackListBase<Callback<void(A1, A2, A3)> > { - public: - typedef Callback<void(A1, A2, A3)> CallbackType; - - CallbackList() {} - - void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3) { - typename internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); - CallbackType* cb; - while ((cb = it.GetNext()) != NULL) { - cb->Run(a1, a2, a3); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackList); -}; - -template <typename A1, typename A2, typename A3, typename A4> -class CallbackList<void(A1, A2, A3, A4)> - : public internal::CallbackListBase<Callback<void(A1, A2, A3, A4)> > { - public: - typedef Callback<void(A1, A2, A3, A4)> CallbackType; - - CallbackList() {} - - void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3, - typename internal::CallbackParamTraits<A4>::ForwardType a4) { - typename internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); - CallbackType* cb; - while ((cb = it.GetNext()) != NULL) { - cb->Run(a1, a2, a3, a4); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackList); -}; - -template <typename A1, typename A2, typename A3, typename A4, typename A5> -class CallbackList<void(A1, A2, A3, A4, A5)> - : public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5)> > { - public: - typedef Callback<void(A1, A2, A3, A4, A5)> CallbackType; - - CallbackList() {} - - void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3, - typename internal::CallbackParamTraits<A4>::ForwardType a4, - typename internal::CallbackParamTraits<A5>::ForwardType a5) { - typename internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); - CallbackType* cb; - while ((cb = it.GetNext()) != NULL) { - cb->Run(a1, a2, a3, a4, a5); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackList); -}; - -template <typename A1, typename A2, typename A3, typename A4, typename A5, - typename A6> -class CallbackList<void(A1, A2, A3, A4, A5, A6)> - : public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5, - A6)> > { - public: - typedef Callback<void(A1, A2, A3, A4, A5, A6)> CallbackType; - - CallbackList() {} - - void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3, - typename internal::CallbackParamTraits<A4>::ForwardType a4, - typename internal::CallbackParamTraits<A5>::ForwardType a5, - typename internal::CallbackParamTraits<A6>::ForwardType a6) { - typename internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); - CallbackType* cb; - while ((cb = it.GetNext()) != NULL) { - cb->Run(a1, a2, a3, a4, a5, a6); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackList); -}; - -template <typename A1, typename A2, typename A3, typename A4, typename A5, - typename A6, typename A7> -class CallbackList<void(A1, A2, A3, A4, A5, A6, A7)> - : public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5, A6, - A7)> > { - public: - typedef Callback<void(A1, A2, A3, A4, A5, A6, A7)> CallbackType; - - CallbackList() {} - - void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1, - typename internal::CallbackParamTraits<A2>::ForwardType a2, - typename internal::CallbackParamTraits<A3>::ForwardType a3, - typename internal::CallbackParamTraits<A4>::ForwardType a4, - typename internal::CallbackParamTraits<A5>::ForwardType a5, - typename internal::CallbackParamTraits<A6>::ForwardType a6, - typename internal::CallbackParamTraits<A7>::ForwardType a7) { - typename internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); - CallbackType* cb; - while ((cb = it.GetNext()) != NULL) { - cb->Run(a1, a2, a3, a4, a5, a6, a7); + cb->Run(args...); } }
diff --git a/base/callback_list.h.pump b/base/callback_list.h.pump deleted file mode 100644 index d7f8473..0000000 --- a/base/callback_list.h.pump +++ /dev/null
@@ -1,269 +0,0 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ - -$$ See comment for MAX_ARITY in base/bind.h.pump. -$var MAX_ARITY = 7 - -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CALLBACK_LIST_H_ -#define BASE_CALLBACK_LIST_H_ - -#include <list> - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/callback_internal.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" - -// OVERVIEW: -// -// A container for a list of callbacks. Unlike a normal STL vector or list, -// this container can be modified during iteration without invalidating the -// iterator. It safely handles the case of a callback removing itself -// or another callback from the list while callbacks are being run. -// -// TYPICAL USAGE: -// -// class MyWidget { -// public: -// ... -// -// typedef base::Callback<void(const Foo&)> OnFooCallback; -// -// scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription> -// RegisterCallback(const OnFooCallback& cb) { -// return callback_list_.Add(cb); -// } -// -// private: -// void NotifyFoo(const Foo& foo) { -// callback_list_.Notify(foo); -// } -// -// base::CallbackList<void(const Foo&)> callback_list_; -// -// DISALLOW_COPY_AND_ASSIGN(MyWidget); -// }; -// -// -// class MyWidgetListener { -// public: -// MyWidgetListener::MyWidgetListener() { -// foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback( -// base::Bind(&MyWidgetListener::OnFoo, this))); -// } -// -// MyWidgetListener::~MyWidgetListener() { -// // Subscription gets deleted automatically and will deregister -// // the callback in the process. -// } -// -// private: -// void OnFoo(const Foo& foo) { -// // Do something. -// } -// -// scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription> -// foo_subscription_; -// -// DISALLOW_COPY_AND_ASSIGN(MyWidgetListener); -// }; - -namespace base { - -namespace internal { - -template <typename CallbackType> -class CallbackListBase { - public: - class Subscription { - public: - Subscription(CallbackListBase<CallbackType>* list, - typename std::list<CallbackType>::iterator iter) - : list_(list), - iter_(iter) { - } - - ~Subscription() { - if (list_->active_iterator_count_) { - iter_->Reset(); - } else { - list_->callbacks_.erase(iter_); - if (!list_->removal_callback_.is_null()) - list_->removal_callback_.Run(); - } - } - - private: - CallbackListBase<CallbackType>* list_; - typename std::list<CallbackType>::iterator iter_; - - DISALLOW_COPY_AND_ASSIGN(Subscription); - }; - - // Add a callback to the list. The callback will remain registered until the - // returned Subscription is destroyed, which must occur before the - // CallbackList is destroyed. - scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT { - DCHECK(!cb.is_null()); - return scoped_ptr<Subscription>( - new Subscription(this, callbacks_.insert(callbacks_.end(), cb))); - } - - // Sets a callback which will be run when a subscription list is changed. - void set_removal_callback(const Closure& callback) { - removal_callback_ = callback; - } - - // Returns true if there are no subscriptions. This is only valid to call when - // not looping through the list. - bool empty() { - DCHECK_EQ(0, active_iterator_count_); - return callbacks_.empty(); - } - - protected: - // An iterator class that can be used to access the list of callbacks. - class Iterator { - public: - explicit Iterator(CallbackListBase<CallbackType>* list) - : list_(list), - list_iter_(list_->callbacks_.begin()) { - ++list_->active_iterator_count_; - } - - Iterator(const Iterator& iter) - : list_(iter.list_), - list_iter_(iter.list_iter_) { - ++list_->active_iterator_count_; - } - - ~Iterator() { - if (list_ && --list_->active_iterator_count_ == 0) { - list_->Compact(); - } - } - - CallbackType* GetNext() { - while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null()) - ++list_iter_; - - CallbackType* cb = NULL; - if (list_iter_ != list_->callbacks_.end()) { - cb = &(*list_iter_); - ++list_iter_; - } - return cb; - } - - private: - CallbackListBase<CallbackType>* list_; - typename std::list<CallbackType>::iterator list_iter_; - }; - - CallbackListBase() : active_iterator_count_(0) {} - - ~CallbackListBase() { - DCHECK_EQ(0, active_iterator_count_); - DCHECK_EQ(0U, callbacks_.size()); - } - - // Returns an instance of a CallbackListBase::Iterator which can be used - // to run callbacks. - Iterator GetIterator() { - return Iterator(this); - } - - // Compact the list: remove any entries which were NULLed out during - // iteration. - void Compact() { - typename std::list<CallbackType>::iterator it = callbacks_.begin(); - bool updated = false; - while (it != callbacks_.end()) { - if ((*it).is_null()) { - updated = true; - it = callbacks_.erase(it); - } else { - ++it; - } - - if (updated && !removal_callback_.is_null()) - removal_callback_.Run(); - } - } - - private: - std::list<CallbackType> callbacks_; - int active_iterator_count_; - Closure removal_callback_; - - DISALLOW_COPY_AND_ASSIGN(CallbackListBase); -}; - -} // namespace internal - -template <typename Sig> class CallbackList; - - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$range ARG 1..ARITY - -$if ARITY == 0 [[ -template <> -class CallbackList<void(void)> - : public internal::CallbackListBase<Callback<void(void)> > { -]] $else [[ -template <$for ARG , [[typename A$(ARG)]]> -class CallbackList<void($for ARG , [[A$(ARG)]])> - : public internal::CallbackListBase<Callback<void($for ARG , [[A$(ARG)]])> > { -]] - - public: -$if ARITY == 0 [[ - - typedef Callback<void(void)> CallbackType; -]] $else [[ - - typedef Callback<void($for ARG , [[A$(ARG)]])> CallbackType; -]] - - - CallbackList() {} - - void Notify($for ARG , - [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { -$if ARITY == 0 [[ - - internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); -]] $else [[ - - typename internal::CallbackListBase<CallbackType>::Iterator it = - this->GetIterator(); -]] - - CallbackType* cb; - while ((cb = it.GetNext()) != NULL) { - cb->Run($for ARG , [[a$(ARG)]]); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackList); -}; - - -]] $$ for ARITY -} // namespace base - -#endif // BASE_CALLBACK_LIST_H_
diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc index d5d1b83..142f891 100644 --- a/base/debug/proc_maps_linux_unittest.cc +++ b/base/debug/proc_maps_linux_unittest.cc
@@ -7,6 +7,7 @@ #include "base/path_service.h" #include "base/strings/stringprintf.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h" +#include "base/threading/platform_thread.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -197,6 +198,14 @@ bool found_exe = false; bool found_stack = false; bool found_address = false; + + // Valgrind uses its own allocated stacks instead of the kernel-provided stack + // without letting the kernel know via prctl(PR_SET_MM_START_STACK). This + // causes the kernel to use [stack:TID] format. See http://crbug.com/431702 + // for details. + std::string stack_with_tid = + StringPrintf("[stack:%d]", PlatformThread::CurrentId()); + for (size_t i = 0; i < regions.size(); ++i) { if (regions[i].path == exe_path.value()) { // It's OK to find the executable mapped multiple times as there'll be @@ -204,17 +213,23 @@ found_exe = true; } + bool is_correct_stack = false; if (regions[i].path == "[stack]") { - // Only check if |address| lies within the real stack when not running - // Valgrind, otherwise |address| will be on a stack that Valgrind creates. - if (!RunningOnValgrind()) { - EXPECT_GE(address, regions[i].start); - EXPECT_LT(address, regions[i].end); - } + is_correct_stack = true; + EXPECT_FALSE(RunningOnValgrind()); + EXPECT_GE(address, regions[i].start); + EXPECT_LT(address, regions[i].end); + } else if (regions[i].path == stack_with_tid) { + is_correct_stack = true; + EXPECT_TRUE(RunningOnValgrind()); + } + if (is_correct_stack) { + // Note that the stack is executable when it is created by Valgrind. EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ); EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE); - EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE); + EXPECT_EQ(RunningOnValgrind(), + (regions[i].permissions & MappedMemoryRegion::EXECUTE) != 0); EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE); EXPECT_FALSE(found_stack) << "Found duplicate stacks"; found_stack = true;
diff --git a/base/files/file_path.h b/base/files/file_path.h index ad42b95..6890866 100644 --- a/base/files/file_path.h +++ b/base/files/file_path.h
@@ -107,6 +107,7 @@ #include <vector> #include "base/base_export.h" +#include "base/compiler_specific.h" #include "base/containers/hash_tables.h" #include "base/strings/string16.h" #include "base/strings/string_piece.h" // For implicit conversions.
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc index 95a16f2..6ee4e76 100644 --- a/base/logging_unittest.cc +++ b/base/logging_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/basictypes.h" +#include "base/compiler_specific.h" #include "base/logging.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/base/mac/scoped_mach_port.cc b/base/mac/scoped_mach_port.cc index de94602..13307f2 100644 --- a/base/mac/scoped_mach_port.cc +++ b/base/mac/scoped_mach_port.cc
@@ -25,6 +25,14 @@ << "ScopedMachReceiveRight mach_port_mod_refs"; } +// static +void PortSetTraits::Free(mach_port_t port) { + kern_return_t kr = + mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, -1); + MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) + << "ScopedMachPortSet mach_port_mod_refs"; +} + } // namespace internal } // namespace mac } // namespace base
diff --git a/base/mac/scoped_mach_port.h b/base/mac/scoped_mach_port.h index 36087c9..9ef90d6 100644 --- a/base/mac/scoped_mach_port.h +++ b/base/mac/scoped_mach_port.h
@@ -31,6 +31,14 @@ static void Free(mach_port_t port); }; +struct PortSetTraits { + static mach_port_t InvalidValue() { + return MACH_PORT_NULL; + } + + static void Free(mach_port_t port); +}; + } // namespace internal // A scoper for handling a Mach port that names a send right. Send rights are @@ -59,6 +67,19 @@ operator mach_port_t() const { return get(); } }; +// A scoper for handling a Mach port set. A port set can have only one +// reference. This takes ownership of that single reference on construction and +// destroys the port set on destruction. Destroying a port set does not destroy +// the receive rights that are members of the port set. +class BASE_EXPORT ScopedMachPortSet : + public ScopedGeneric<mach_port_t, internal::PortSetTraits> { + public: + explicit ScopedMachPortSet(mach_port_t port = traits_type::InvalidValue()) + : ScopedGeneric(port) {} + + operator mach_port_t() const { return get(); } +}; + } // namespace mac } // namespace base
diff --git a/base/macros.h b/base/macros.h index b6240da..15408bc 100644 --- a/base/macros.h +++ b/base/macros.h
@@ -13,8 +13,6 @@ #include <stddef.h> // For size_t. #include <string.h> // For memcpy. -#include "base/compiler_specific.h" // For ALLOW_UNUSED. - // Put this in the private: declarations for a class to be uncopyable. #define DISALLOW_COPY(TypeName) \ TypeName(const TypeName&)
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc index 62617c5..23c28d4 100644 --- a/base/metrics/statistics_recorder.cc +++ b/base/metrics/statistics_recorder.cc
@@ -289,9 +289,8 @@ void StatisticsRecorder::DumpHistogramsToVlog(void* instance) { DCHECK(VLOG_IS_ON(1)); - StatisticsRecorder* me = reinterpret_cast<StatisticsRecorder*>(instance); string output; - me->WriteGraph(std::string(), &output); + StatisticsRecorder::WriteGraph(std::string(), &output); VLOG(1) << output; }
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h index 3eb3604..ca23ac8 100644 --- a/base/process/process_metrics.h +++ b/base/process/process_metrics.h
@@ -234,7 +234,7 @@ #if defined(OS_POSIX) // Returns the maximum number of file descriptors that can be open by a process // at once. If the number is unavailable, a conservative best guess is returned. -size_t GetMaxFds(); +BASE_EXPORT size_t GetMaxFds(); // Sets the file descriptor soft limit to |max_descriptors| or the OS hard // limit, whichever is lower.
diff --git a/base/profiler/scoped_tracker.cc b/base/profiler/scoped_tracker.cc index 26b17c0..d15b7de 100644 --- a/base/profiler/scoped_tracker.cc +++ b/base/profiler/scoped_tracker.cc
@@ -12,13 +12,6 @@ ScopedProfile::Mode g_scoped_profile_mode = ScopedProfile::DISABLED; -// Executes |callback|, augmenting it with provided |location|. -void ExecuteAndTrackCallback(const Location& location, - const base::Closure& callback) { - ScopedProfile tracking_profile(location, ScopedProfile::ENABLED); - callback.Run(); -} - } // namespace // static @@ -26,15 +19,6 @@ g_scoped_profile_mode = ScopedProfile::ENABLED; } -// static -base::Closure ScopedTracker::TrackCallback(const Location& location, - const base::Closure& callback) { - if (g_scoped_profile_mode != ScopedProfile::ENABLED) - return callback; - - return base::Bind(ExecuteAndTrackCallback, location, callback); -} - ScopedTracker::ScopedTracker(const Location& location) : scoped_profile_(location, g_scoped_profile_mode) { }
diff --git a/base/profiler/scoped_tracker.h b/base/profiler/scoped_tracker.h index f83654e..23e2f07 100644 --- a/base/profiler/scoped_tracker.h +++ b/base/profiler/scoped_tracker.h
@@ -10,6 +10,7 @@ // found using profiler data. #include "base/base_export.h" +#include "base/bind.h" #include "base/callback_forward.h" #include "base/location.h" #include "base/profiler/scoped_profile.h" @@ -47,10 +48,24 @@ // many possible callbacks, but they come from a relatively small number of // places. We can instrument these few places and at least know which one // passes the janky callback. - static base::Closure TrackCallback(const Location& location, - const base::Closure& callback); + template <typename P1> + static base::Callback<void(P1)> TrackCallback( + const Location& location, + const base::Callback<void(P1)>& callback) { + return base::Bind(&ScopedTracker::ExecuteAndTrackCallback<P1>, location, + callback); + } private: + // Executes |callback|, augmenting it with provided |location|. + template <typename P1> + static void ExecuteAndTrackCallback(const Location& location, + const base::Callback<void(P1)>& callback, + P1 p1) { + ScopedTracker tracking_profile(location); + callback.Run(p1); + } + const ScopedProfile scoped_profile_; DISALLOW_COPY_AND_ASSIGN(ScopedTracker);
diff --git a/base/security_unittest.cc b/base/security_unittest.cc index a6d3480..d786273 100644 --- a/base/security_unittest.cc +++ b/base/security_unittest.cc
@@ -194,7 +194,9 @@ } // On windows, the compiler prevents static array sizes of more than // 0x7fffffff (error C2148). -#if !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS) +#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) + ALLOW_UNUSED_LOCAL(kDynamicArraySize); +#else { scoped_ptr<char[][kArraySize2]> array_pointer(new (nothrow) char[kDynamicArraySize][kArraySize2]);
diff --git a/base/test/test_shortcut_win.cc b/base/test/test_shortcut_win.cc index c772d87..eb074a3 100644 --- a/base/test/test_shortcut_win.cc +++ b/base/test/test_shortcut_win.cc
@@ -67,7 +67,7 @@ if (FAILED(hr)) return; - EXPECT_TRUE(SUCCEEDED(hr = i_persist_file.QueryFrom(i_shell_link))); + EXPECT_TRUE(SUCCEEDED(hr = i_persist_file.QueryFrom(i_shell_link.get()))); if (FAILED(hr)) return; @@ -112,7 +112,7 @@ if (GetVersion() >= VERSION_WIN7) { ScopedComPtr<IPropertyStore> property_store; - EXPECT_TRUE(SUCCEEDED(hr = property_store.QueryFrom(i_shell_link))); + EXPECT_TRUE(SUCCEEDED(hr = property_store.QueryFrom(i_shell_link.get()))); if (FAILED(hr)) return;
diff --git a/base/tracked_objects.h b/base/tracked_objects.h index 723fb91..eb38df6 100644 --- a/base/tracked_objects.h +++ b/base/tracked_objects.h
@@ -43,7 +43,7 @@ // computational cost is associated with obtaining start and stop times for // instances as they are created and destroyed. // -// The following describes the lifecycle of tracking an instance. +// The following describes the life cycle of tracking an instance. // // First off, when the instance is created, the FROM_HERE macro is expanded // to specify the birth place (file, line, function) where the instance was @@ -96,9 +96,9 @@ // lock such DeathData instances. (i.e., these accumulated stats in a DeathData // instance are exclusively updated by the singular owning thread). // -// With the above lifecycle description complete, the major remaining detail is -// explaining how each thread maintains a list of DeathData instances, and of -// Births instances, and is able to avoid additional (redundant/unnecessary) +// With the above life cycle description complete, the major remaining detail +// is explaining how each thread maintains a list of DeathData instances, and +// of Births instances, and is able to avoid additional (redundant/unnecessary) // allocations. // // Each thread maintains a list of data items specific to that thread in a @@ -119,7 +119,7 @@ // which ensures that any prior acquisition of the list is valid (i.e., the // holder can iterate over it without fear of it changing, or the necessity of // using an additional lock. Iterations are actually pretty rare (used -// primarilly for cleanup, or snapshotting data for display), so this lock has +// primarily for cleanup, or snapshotting data for display), so this lock has // very little global performance impact. // // The above description tries to define the high performance (run time) @@ -156,7 +156,7 @@ // example, match with the number of durations we accumulated). The advantage // to having fast (non-atomic) updates of the data outweighs the minimal risk of // a singular corrupt statistic snapshot (only the snapshot could be corrupt, -// not the underlying and ongoing statistic). In constrast, pointer data that +// not the underlying and ongoing statistic). In contrast, pointer data that // is accessed during snapshotting is completely invariant, and hence is // perfectly acquired (i.e., no potential corruption, and no risk of a bad // memory reference). @@ -167,9 +167,9 @@ // them will continue to be asynchronous). We had an implementation of this in // the past, but the difficulty is dealing with message loops being terminated. // We can *try* to spam the available threads via some message loop proxy to -// achieve this feat, and it *might* be valuable when we are colecting data for -// upload via UMA (where correctness of data may be more significant than for a -// single screen of about:profiler). +// achieve this feat, and it *might* be valuable when we are collecting data +// for upload via UMA (where correctness of data may be more significant than +// for a single screen of about:profiler). // // TODO(jar): We should support (optionally) the recording of parent-child // relationships for tasks. This should be done by detecting what tasks are @@ -181,7 +181,7 @@ // TODO(jar): We need to store DataCollections, and provide facilities for // taking the difference between two gathered DataCollections. For now, we're // just adding a hack that Reset()s to zero all counts and stats. This is also -// done in a slighly thread-unsafe fashion, as the resetting is done +// done in a slightly thread-unsafe fashion, as the resetting is done // asynchronously relative to ongoing updates (but all data is 32 bit in size). // For basic profiling, this will work "most of the time," and should be // sufficient... but storing away DataCollections is the "right way" to do this. @@ -361,7 +361,7 @@ enum Status { UNINITIALIZED, // PRistine, link-time state before running. DORMANT_DURING_TESTS, // Only used during testing. - DEACTIVATED, // No longer recording profling. + DEACTIVATED, // No longer recording profiling. PROFILING_ACTIVE, // Recording profiles (no parent-child links). PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links. STATUS_LAST = PROFILING_CHILDREN_ACTIVE @@ -551,7 +551,7 @@ // Using our lock, make a copy of the specified maps. This call may be made // on non-local threads, which necessitate the use of the lock to prevent - // the map(s) from being reallocaed while they are copied. If |reset_max| is + // the map(s) from being reallocated while they are copied. If |reset_max| is // true, then, just after we copy the DeathMap, we will set the max values to // zero in the active DeathMap (not the snapshot). void SnapshotMaps(bool reset_max, @@ -593,7 +593,7 @@ static base::ThreadLocalStorage::StaticSlot tls_index_; // List of ThreadData instances for use with worker threads. When a worker - // thread is done (terminated), we push it onto this llist. When a new worker + // thread is done (terminated), we push it onto this list. When a new worker // thread is created, we first try to re-use a ThreadData instance from the // list, and if none are available, construct a new one. // This is only accessed while list_lock_ is held. @@ -676,7 +676,7 @@ // not yet concluded with a NowForEndOfRun(). Usually this stack is one deep, // but if a scoped region is profiled, or <sigh> a task runs a nested-message // loop, then the stack can grow larger. Note that we don't try to deduct - // time in nested porfiles, as our current timer is based on wall-clock time, + // time in nested profiles, as our current timer is based on wall-clock time, // and not CPU time (and we're hopeful that nested timing won't be a // significant additional cost). ParentStack parent_stack_;
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc index eef299b..eb26cea 100644 --- a/base/win/shortcut.cc +++ b/base/win/shortcut.cc
@@ -33,7 +33,7 @@ i_persist_file->Release(); if (FAILED(i_shell_link->CreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER)) || - FAILED(i_persist_file->QueryFrom(*i_shell_link)) || + FAILED(i_persist_file->QueryFrom(i_shell_link->get())) || (shortcut && FAILED((*i_persist_file)->Load(shortcut, STGM_READWRITE)))) { i_shell_link->Release(); i_persist_file->Release(); @@ -129,15 +129,17 @@ if ((has_app_id || has_dual_mode) && GetVersion() >= VERSION_WIN7) { ScopedComPtr<IPropertyStore> property_store; - if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get()) + if (FAILED(property_store.QueryFrom(i_shell_link.get())) || + !property_store.get()) return false; if (has_app_id && - !SetAppIdForPropertyStore(property_store, properties.app_id.c_str())) { + !SetAppIdForPropertyStore(property_store.get(), + properties.app_id.c_str())) { return false; } if (has_dual_mode && - !SetBooleanValueForPropertyStore(property_store, + !SetBooleanValueForPropertyStore(property_store.get(), PKEY_AppUserModel_IsDualMode, properties.dual_mode)) { return false; @@ -192,7 +194,7 @@ ScopedComPtr<IPersistFile> persist; // Query IShellLink for the IPersistFile interface. - if (FAILED(persist.QueryFrom(i_shell_link))) + if (FAILED(persist.QueryFrom(i_shell_link.get()))) return false; // Load the shell link. @@ -239,7 +241,7 @@ if ((options & ShortcutProperties::PROPERTIES_WIN7) && GetVersion() >= VERSION_WIN7) { ScopedComPtr<IPropertyStore> property_store; - if (FAILED(property_store.QueryFrom(i_shell_link))) + if (FAILED(property_store.QueryFrom(i_shell_link.get()))) return false; if (options & ShortcutProperties::PROPERTIES_APP_ID) {
diff --git a/build/all.gyp b/build/all.gyp index c3443f9..5fe54d7 100644 --- a/build/all.gyp +++ b/build/all.gyp
@@ -42,13 +42,13 @@ # NOTE: This list of targets is present because # mojo_base.gyp:mojo_base cannot be built on iOS, as # javascript-related targets cause v8 to be built. - '../mojo/edk/mojo_edk.gyp:mojo_public_bindings_unittests', - '../mojo/edk/mojo_edk.gyp:mojo_public_environment_unittests', - '../mojo/edk/mojo_edk.gyp:mojo_public_system_perftests', - '../mojo/edk/mojo_edk.gyp:mojo_public_system_unittests', - '../mojo/edk/mojo_edk.gyp:mojo_public_utility_unittests', + '../mojo/edk/mojo_edk_tests.gyp:mojo_public_bindings_unittests', + '../mojo/edk/mojo_edk_tests.gyp:mojo_public_environment_unittests', + '../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_perftests', + '../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_unittests', + '../mojo/edk/mojo_edk_tests.gyp:mojo_public_utility_unittests', '../mojo/edk/mojo_edk.gyp:mojo_system_impl', - '../mojo/edk/mojo_edk.gyp:mojo_system_unittests', + '../mojo/edk/mojo_edk_tests.gyp:mojo_system_unittests', '../mojo/mojo_base.gyp:mojo_common_lib', '../mojo/mojo_base.gyp:mojo_common_unittests', '../mojo/public/mojo_public.gyp:mojo_cpp_bindings', @@ -405,6 +405,11 @@ }], ], }], + ['chromeos==1', { + 'dependencies': [ + '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_unittests', + ], + }], ['OS=="linux"', { 'dependencies': [ '../dbus/dbus.gyp:dbus_unittests', @@ -738,6 +743,11 @@ '../skia/tools/clusterfuzz-data/fuzzers/filter_fuzzer/filter_fuzzer.gyp:filter_fuzzer', ], }], # internal_filter_fuzzer + ['clang==1', { + 'dependencies': [ + 'sanitizers/sanitizers.gyp:llvm-symbolizer', + ], + }], ['OS=="win" and fastbuild==0 and target_arch=="ia32" and syzyasan==1', { 'dependencies': [ '../chrome/chrome_syzygy.gyp:chrome_dll_syzygy', @@ -856,6 +866,7 @@ ['enable_webrtc==1 and "<(libpeer_target_type)"=="static_library"', { 'dependencies': [ '../components/devtools_bridge.gyp:devtools_bridge_tests_apk', + '../components/devtools_bridge.gyp:libdevtools_bridge_browsertests', ], }], ], @@ -871,6 +882,7 @@ '../tools/android/android_tools.gyp:memconsumer', # Unit test bundles packaged as an apk. '../components/devtools_bridge.gyp:devtools_bridge_tests_apk', + '../components/devtools_bridge.gyp:libdevtools_bridge_browsertests', '../content/content_shell_and_tests.gyp:content_browsertests_apk', ], }, # target_name: android_builder_chromium_webrtc @@ -1294,8 +1306,9 @@ }], ['chromeos==1', { 'dependencies': [ - '../chromeos/chromeos.gyp:chromeos_unittests', '../athena/main/athena_main.gyp:*', + '../chromeos/chromeos.gyp:chromeos_unittests', + '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_unittests', ], }], ['use_ozone==1', {
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py index bb57e54..f226b37 100644 --- a/build/android/PRESUBMIT.py +++ b/build/android/PRESUBMIT.py
@@ -64,6 +64,7 @@ J('pylib', 'device', 'device_utils_test.py'), J('pylib', 'gtest', 'test_package_test.py'), J('pylib', 'instrumentation', 'test_runner_test.py'), + J('pylib', 'utils', 'md5sum_test.py'), ], env=pylib_test_env)) output.extend(_CheckDeletionsOnlyFiles(input_api, output_api))
diff --git a/build/android/adb_logcat_monitor.py b/build/android/adb_logcat_monitor.py index a5ae785..d3cc67d 100755 --- a/build/android/adb_logcat_monitor.py +++ b/build/android/adb_logcat_monitor.py
@@ -83,7 +83,7 @@ stderr=subprocess.PIPE).communicate() if err: logging.warning('adb device error %s', err.strip()) - return re.findall('^(\S+)\tdevice$', out, re.MULTILINE) + return re.findall('^(\\S+)\tdevice$', out, re.MULTILINE) except TimeoutException: logging.warning('"adb devices" command timed out') return [] @@ -136,7 +136,7 @@ time.sleep(5) except SigtermError: logging.info('Received SIGTERM, shutting down') - except: + except: # pylint: disable=bare-except logging.exception('Unexpected exception in main.') finally: for process, _ in devices.itervalues():
diff --git a/build/android/adb_reverse_forwarder.py b/build/android/adb_reverse_forwarder.py index c1d9551..1958fdd 100755 --- a/build/android/adb_reverse_forwarder.py +++ b/build/android/adb_reverse_forwarder.py
@@ -61,7 +61,7 @@ else: if not devices: raise Exception('Error: no connected devices') - print("No device specified. Defaulting to " + devices[0]) + print "No device specified. Defaulting to " + devices[0] device = device_utils.DeviceUtils(devices[0]) constants.SetBuildType(options.build_type)
diff --git a/build/android/avd.py b/build/android/avd.py index ddff11a..c45544f 100755 --- a/build/android/avd.py +++ b/build/android/avd.py
@@ -70,8 +70,8 @@ android = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk', 'tools', 'android') avds_output = cmd_helper.GetCmdOutput([android, 'list', 'avd']) - names = re.findall('Name: (\w+)', avds_output) - api_levels = re.findall('API level (\d+)', avds_output) + names = re.findall(r'Name: (\w+)', avds_output) + api_levels = re.findall(r'API level (\d+)', avds_output) try: avd_index = names.index(options.name) except ValueError:
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py index d98c1dd..a72a0c7 100755 --- a/build/android/buildbot/bb_device_status_check.py +++ b/build/android/buildbot/bb_device_status_check.py
@@ -57,7 +57,7 @@ battery_info = {} logging.error('Unable to obtain battery info for %s, %s', serial, e) - def _GetData(re_expression, line, lambda_function=lambda x:x): + def _GetData(re_expression, line, lambda_function=lambda x: x): if not line: return 'Unknown' found = re.findall(re_expression, line) @@ -66,7 +66,7 @@ return 'Unknown' battery_level = int(battery_info.get('level', 100)) - imei_slice = _GetData('Device ID = (\d+)', + imei_slice = _GetData(r'Device ID = (\d+)', device_adb.old_interface.GetSubscriberInfo(), lambda x: x[-6:]) report = ['Device %s (%s)' % (serial, device_type), @@ -151,7 +151,7 @@ os.environ.get('BUILDBOT_BUILDERNAME'), os.environ.get('BUILDBOT_BUILDNUMBER')) msg = ('Please reboot the following devices:\n%s' % - '\n'.join(map(str,new_missing_devs))) + '\n'.join(map(str, new_missing_devs))) SendEmail(from_address, to_addresses, cc_addresses, subject, msg) all_known_devices = list(set(adb_online_devs) | set(last_devices)) @@ -216,10 +216,10 @@ lsusb_proc = bb_utils.SpawnCmd(['lsusb'], stdout=subprocess.PIPE) lsusb_output, _ = lsusb_proc.communicate() if lsusb_proc.returncode: - print ('Error: Could not get list of USB ports (i.e. lsusb).') + print 'Error: Could not get list of USB ports (i.e. lsusb).' return lsusb_proc.returncode - usb_devices = [re.findall('Bus (\d\d\d) Device (\d\d\d)', lsusb_line)[0] + usb_devices = [re.findall(r'Bus (\d\d\d) Device (\d\d\d)', lsusb_line)[0] for lsusb_line in lsusb_output.strip().split('\n')] all_restarted = True
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py index 530512a..3142b23 100755 --- a/build/android/buildbot/bb_device_steps.py +++ b/build/android/buildbot/bb_device_steps.py
@@ -81,8 +81,8 @@ ]) VALID_TESTS = set(['chromedriver', 'chrome_proxy', 'gpu', - 'telemetry_perf_unittests', 'ui', 'unit', 'webkit', - 'webkit_layout', 'python_unittests']) + 'telemetry_unittests', 'telemetry_perf_unittests', 'ui', + 'unit', 'webkit', 'webkit_layout', 'python_unittests']) RunCmd = bb_utils.RunCmd @@ -190,19 +190,23 @@ RunCmd(['tools/chrome_proxy/run_tests'] + args) -def RunTelemetryPerfUnitTests(options): - """Runs the telemetry perf unit tests. +def RunTelemetryTests(options, step_name, run_tests_path): + """Runs either telemetry_perf_unittests or telemetry_unittests. Args: options: options object. + step_name: either 'telemetry_unittests' or 'telemetry_perf_unittests' + run_tests_path: path to run_tests script (tools/perf/run_tests for + perf_unittests and tools/telemetry/run_tests for + telemetry_unittests) """ InstallApk(options, INSTRUMENTATION_TESTS['ChromeShell'], False) args = ['--browser', 'android-chrome-shell'] devices = android_commands.GetAttachedDevices() if devices: args = args + ['--device', devices[0]] - bb_annotations.PrintNamedStep('telemetry_perf_unittests') - RunCmd(['tools/perf/run_tests'] + args) + bb_annotations.PrintNamedStep(step_name) + RunCmd([run_tests_path] + args) def InstallApk(options, test, print_step=False): @@ -472,6 +476,14 @@ RunTestSuites(options, suites) +def RunTelemetryUnitTests(options): + RunTelemetryTests(options, 'telemetry_unittests', 'tools/telemetry/run_tests') + + +def RunTelemetryPerfUnitTests(options): + RunTelemetryTests(options, 'telemetry_perf_unittests', 'tools/perf/run_tests') + + def RunInstrumentationTests(options): for test in INSTRUMENTATION_TESTS.itervalues(): RunInstrumentationSuite(options, test) @@ -529,6 +541,7 @@ ('chrome_proxy', RunChromeProxyTests), ('gpu', RunGPUTests), ('python_unittests', RunPythonUnitTests), + ('telemetry_unittests', RunTelemetryUnitTests), ('telemetry_perf_unittests', RunTelemetryPerfUnitTests), ('ui', RunInstrumentationTests), ('unit', RunUnitTests), @@ -582,7 +595,7 @@ # Print logcat, kill logcat monitor bb_annotations.PrintNamedStep('logcat_dump') logcat_file = os.path.join(CHROME_OUT_DIR, options.target, 'full_log.txt') - RunCmd([SrcPath('build' , 'android', 'adb_logcat_printer.py'), + RunCmd([SrcPath('build', 'android', 'adb_logcat_printer.py'), '--output-path', logcat_file, LOGCAT_DIR]) gs_path = MakeGSPath(options, 'chromium-android/logcat_dumps') RunCmd([bb_utils.GSUTIL_PATH, 'cp', '-z', 'txt', logcat_file, @@ -693,9 +706,9 @@ '--chrome-output-dir', help='Chrome output directory to be used while bisecting.') - parser.add_option('--disable-stack-tool', action='store_true', + parser.add_option('--disable-stack-tool', action='store_true', help='Do not run stack tool.') - parser.add_option('--asan-symbolize', action='store_true', + parser.add_option('--asan-symbolize', action='store_true', help='Run stack tool for ASAN') parser.add_option('--cleanup', action='store_true', help='Delete out/<target> directory at the end of the run.')
diff --git a/build/android/buildbot/bb_run_bot.py b/build/android/buildbot/bb_run_bot.py index 8c853e7..abdd2be 100755 --- a/build/android/buildbot/bb_run_bot.py +++ b/build/android/buildbot/bb_run_bot.py
@@ -132,10 +132,10 @@ os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, os.pardir, 'bisect', 'src', 'out')) B = BotConfig - H = (lambda steps, extra_args=None, extra_gyp=None, target_arch=None : + H = (lambda steps, extra_args=None, extra_gyp=None, target_arch=None: HostConfig('build/android/buildbot/bb_host_steps.py', steps, extra_args, extra_gyp, target_arch)) - T = (lambda tests, extra_args=None : + T = (lambda tests, extra_args=None: TestConfig('build/android/buildbot/bb_device_steps.py', tests, extra_args)) @@ -150,7 +150,7 @@ T(std_tests + telemetry_tests + chrome_proxy_tests, ['--cleanup', flakiness_server])), B('main-tests', H(std_test_steps), - T(std_tests,['--cleanup', flakiness_server])), + T(std_tests, ['--cleanup', flakiness_server])), # Other waterfalls B('asan-builder-tests', H(compile_step, @@ -167,7 +167,7 @@ extra_gyp='emma_coverage=1')), B('x86-builder-dbg', H(compile_step + std_host_tests, target_arch='ia32')), - B('fyi-builder-rel', H(std_build_steps, experimental)), + B('fyi-builder-rel', H(std_build_steps, experimental)), B('fyi-tests', H(std_test_steps), T(std_tests + python_unittests, ['--experimental', flakiness_server, @@ -234,7 +234,7 @@ def GetBestMatch(id_map, id): config = id_map.get(id) if not config: - substring_matches = filter(lambda x: x in id, id_map.iterkeys()) + substring_matches = [x for x in id_map.iterkeys() if x in id] if substring_matches: max_id = max(substring_matches, key=len) print 'Using config from id="%s" (substring match).' % max_id
diff --git a/build/android/envsetup.sh b/build/android/envsetup.sh index 26960ac..0545330 100755 --- a/build/android/envsetup.sh +++ b/build/android/envsetup.sh
@@ -43,6 +43,9 @@ # Add Android SDK tools to system path. export PATH=$PATH:${ANDROID_SDK_ROOT}/platform-tools + # Add Android utility tools to the system path. + export PATH=$PATH:${ANDROID_SDK_ROOT}/tools/ + # Add Chromium Android development scripts to system path. # Must be after CHROME_SRC is set. export PATH=$PATH:${CHROME_SRC}/build/android
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index d26e6d3..ed68e6c 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -78,6 +78,8 @@ help='Whether this library supports running on the Android platform.') parser.add_option('--requires-android', action='store_true', help='Whether this library requires running on the Android platform.') + parser.add_option('--bypass-platform-checks', action='store_true', + help='Bypass checks for support/require Android platform.') # android library options parser.add_option('--dex-path', help='Path to target\'s dex output.') @@ -149,14 +151,14 @@ deps_info = config['deps_info'] - if options.type == 'java_library': + if options.type == 'java_library' and not options.bypass_platform_checks: deps_info['requires_android'] = options.requires_android deps_info['supports_android'] = options.supports_android deps_require_android = (all_resources_deps + - [d['name'] for d in direct_library_deps if d['requires_android']]) + [d['name'] for d in all_library_deps if d['requires_android']]) deps_not_support_android = ( - [d['name'] for d in direct_library_deps if not d['supports_android']]) + [d['name'] for d in all_library_deps if not d['supports_android']]) if deps_require_android and not options.requires_android: raise Exception('Some deps require building for the Android platform: ' +
diff --git a/build/android/install_emulator_deps.py b/build/android/install_emulator_deps.py index d980c2c..82d1c75 100755 --- a/build/android/install_emulator_deps.py +++ b/build/android/install_emulator_deps.py
@@ -30,7 +30,7 @@ SDK_BASE_URL = 'http://dl.google.com/android/adt' SDK_ZIP = 'adt-bundle-linux-x86_64-20131030.zip' -# pylint: disable=C0301 +# pylint: disable=line-too-long # Android x86 system image from the Intel website: # http://software.intel.com/en-us/articles/intel-eula-x86-android-4-2-jelly-bean-bin # These don't exist prior to Android-15. @@ -41,7 +41,7 @@ 17: 'https://software.intel.com/sites/landingpage/android/sysimg_x86-17_r01.zip', 18: 'https://software.intel.com/sites/landingpage/android/sysimg_x86-18_r01.zip', 19: 'https://software.intel.com/sites/landingpage/android/sysimg_x86-19_r01.zip'} -#pylint: enable=C0301 +#pylint: enable=line-too-long def CheckSDK(): """Check if SDK is already installed. @@ -194,8 +194,8 @@ """ android_binary = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk', 'tools', 'android') - pattern = re.compile('\s*([0-9]+)- SDK Platform Android [\.,0-9]+, API %d.*' % - api_level) + pattern = re.compile( + r'\s*([0-9]+)- SDK Platform Android [\.,0-9]+, API %d.*' % api_level) # Example: # 2- SDK Platform Android 4.3, API 18, revision 2 exit_code, stdout = cmd_helper.GetCmdStatusAndOutput( @@ -206,7 +206,7 @@ match = pattern.match(line) if match: index = match.group(1) - print('package %s corresponds to platform level %d' % (index, api_level)) + print 'package %s corresponds to platform level %d' % (index, api_level) # update sdk --no-ui --filter $INDEX update_command = [android_binary, 'update', 'sdk', '--no-ui', '--filter', index] @@ -218,7 +218,7 @@ raise Exception('License agreement check failed') update_process.sendline('y') if update_process.expect('Done. 1 package installed.') == 0: - print('Successfully installed platform for API level %d' % api_level) + print 'Successfully installed platform for API level %d' % api_level return else: raise Exception('Failed to install platform update') @@ -238,7 +238,7 @@ # run_tests_helper will set logging to INFO or DEBUG # We achieve verbose output by configuring it with 2 (==DEBUG) verbosity = 1 - if (options.verbose): + if options.verbose: verbosity = 2 logging.basicConfig(level=logging.INFO, format='# %(asctime)-15s: %(message)s')
diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py index 560d1d0..0dc8c81 100755 --- a/build/android/provision_devices.py +++ b/build/android/provision_devices.py
@@ -31,12 +31,12 @@ import errors def KillHostHeartbeat(): - ps = subprocess.Popen(['ps', 'aux'], stdout = subprocess.PIPE) + ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE) stdout, _ = ps.communicate() matches = re.findall('\\n.*host_heartbeat.*', stdout) for match in matches: logging.info('An instance of host heart beart running... will kill') - pid = re.findall('(\S+)', match)[1] + pid = re.findall(r'(\S+)', match)[1] subprocess.call(['kill', str(pid)]) @@ -190,8 +190,9 @@ battery_info.get('level', 0)) time.sleep(60) battery_info = device.old_interface.GetBatteryInfo() - # TODO(jbudorick): Tune the timeout per OS version. - device.Reboot(True, timeout=600, retries=0) + if not options.skip_wipe: + # TODO(jbudorick): Tune the timeout per OS version. + device.Reboot(True, timeout=600, retries=0) device.RunShellCommand('date -s %s' % time.strftime('%Y%m%d.%H%M%S', time.gmtime()), as_root=True) @@ -206,7 +207,7 @@ str(device)) # Device black list is reset by bb_device_status_check.py per build. device_blacklist.ExtendBlacklist([str(device)]) - except (device_errors.CommandFailedError): + except device_errors.CommandFailedError: logging.exception('Failed to provision device %s. Adding to blacklist.', str(device)) device_blacklist.ExtendBlacklist([str(device)])
diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py index 6981afc..8d7866d 100644 --- a/build/android/pylib/android_commands.py +++ b/build/android/pylib/android_commands.py
@@ -6,7 +6,7 @@ Assumes adb binary is currently on system path. """ -# pylint: disable-all +# pylint: skip-file import collections import datetime @@ -314,11 +314,7 @@ device: If given, adb commands are only send to the device of this ID. Otherwise commands are sent to all attached devices. """ - adb_dir = os.path.dirname(constants.GetAdbPath()) - if adb_dir and adb_dir not in os.environ['PATH'].split(os.pathsep): - # Required by third_party/android_testrunner to call directly 'adb'. - os.environ['PATH'] += os.pathsep + adb_dir - self._adb = adb_interface.AdbInterface() + self._adb = adb_interface.AdbInterface(constants.GetAdbPath()) if device: self._adb.SetTargetSerial(device) self._device = device
diff --git a/build/android/pylib/base/base_setup.py b/build/android/pylib/base/base_setup.py new file mode 100644 index 0000000..c276822 --- /dev/null +++ b/build/android/pylib/base/base_setup.py
@@ -0,0 +1,62 @@ +# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Base script for doing test setup.""" + +import logging +import os + +from pylib import constants +from pylib import valgrind_tools +from pylib.utils import isolator + +def GenerateDepsDirUsingIsolate(suite_name, isolate_file_path, + isolate_file_paths, deps_exclusion_list): + """Generate the dependency dir for the test suite using isolate. + + Args: + suite_name: Name of the test suite (e.g. base_unittests). + isolate_file_path: .isolate file path to use. If there is a default .isolate + file path for the suite_name, this will override it. + isolate_file_paths: Dictionary with the default .isolate file paths for + the test suites. + deps_exclusion_list: A list of files that are listed as dependencies in the + .isolate files but should not be pushed to the device. + """ + if isolate_file_path: + if os.path.isabs(isolate_file_path): + isolate_abs_path = isolate_file_path + else: + isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, + isolate_file_path) + else: + isolate_rel_path = isolate_file_paths.get(suite_name) + if not isolate_rel_path: + logging.info('Did not find an isolate file for the test suite.') + return + isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, isolate_rel_path) + + isolated_abs_path = os.path.join( + constants.GetOutDirectory(), '%s.isolated' % suite_name) + assert os.path.exists(isolate_abs_path), 'Cannot find %s' % isolate_abs_path + + i = isolator.Isolator(constants.ISOLATE_DEPS_DIR) + i.Clear() + i.Remap(isolate_abs_path, isolated_abs_path) + # We're relying on the fact that timestamps are preserved + # by the remap command (hardlinked). Otherwise, all the data + # will be pushed to the device once we move to using time diff + # instead of md5sum. Perform a sanity check here. + i.VerifyHardlinks() + i.PurgeExcluded(deps_exclusion_list) + i.MoveOutputDeps() + + +def PushDataDeps(device, device_dir, test_options): + valgrind_tools.PushFilesForTool(test_options.tool, device) + if os.path.exists(constants.ISOLATE_DEPS_DIR): + device.PushChangedFiles([ + (os.path.join(constants.ISOLATE_DEPS_DIR, p), + '%s/%s' % (device_dir, p)) + for p in os.listdir(constants.ISOLATE_DEPS_DIR)])
diff --git a/build/android/pylib/base/base_test_result.py b/build/android/pylib/base/base_test_result.py index f9e61a9..f55be02 100644 --- a/build/android/pylib/base/base_test_result.py +++ b/build/android/pylib/base/base_test_result.py
@@ -203,5 +203,5 @@ def DidRunPass(self): """Return whether the test run was successful.""" - return not (self.GetNotPass() - self.GetSkip()) + return not self.GetNotPass() - self.GetSkip()
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py index 6e51b43..4e2eae7 100644 --- a/build/android/pylib/base/base_test_runner.py +++ b/build/android/pylib/base/base_test_runner.py
@@ -70,14 +70,9 @@ """Installs the test package once before all tests are run.""" pass - def PushDataDeps(self): - """Push all data deps to device once before all tests are run.""" - pass - def SetUp(self): """Run once before all tests are run.""" self.InstallTestPackage() - self.PushDataDeps() def TearDown(self): """Run once after all tests are run."""
diff --git a/build/android/pylib/constants.py b/build/android/pylib/constants.py index 29da601..e89a298 100644 --- a/build/android/pylib/constants.py +++ b/build/android/pylib/constants.py
@@ -187,6 +187,7 @@ 'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android'), 'test_modules': [ 'pylib.device.device_utils_test', + 'pylib.utils.md5sum_test', ] }, 'gyp_py_unittests': { @@ -246,8 +247,21 @@ return Wrapper -@_Memoize +def SetAdbPath(adb_path): + os.environ['ADB_PATH'] = adb_path + + def GetAdbPath(): + # Check if a custom adb path as been set. If not, try to find adb + # on the system. + if os.environ.get('ADB_PATH'): + return os.environ.get('ADB_PATH') + else: + return _FindAdbPath() + + +@_Memoize +def _FindAdbPath(): if os.environ.get('ANDROID_SDK_ROOT'): return 'adb' # If envsetup.sh hasn't been sourced and there's no adb in the path, @@ -260,7 +274,6 @@ logging.debug('No adb found in $PATH, fallback to checked in binary.') return os.path.join(ANDROID_SDK_ROOT, 'platform-tools', 'adb') - # Exit codes ERROR_EXIT_CODE = 1 WARNING_EXIT_CODE = 88
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py index e7a8418..c7ea310 100644 --- a/build/android/pylib/device/adb_wrapper.py +++ b/build/android/pylib/device/adb_wrapper.py
@@ -12,6 +12,7 @@ import os from pylib import cmd_helper +from pylib import constants from pylib.device import decorators from pylib.device import device_errors from pylib.utils import timeout_retry @@ -45,11 +46,11 @@ """ self._device_serial = str(device_serial) - # pylint: disable=W0613 + # pylint: disable=unused-argument @classmethod @decorators.WithTimeoutAndRetries def _RunAdbCmd(cls, arg_list, timeout=None, retries=None, check_error=True): - cmd = ['adb'] + arg_list + cmd = [constants.GetAdbPath()] + arg_list exit_code, output = cmd_helper.GetCmdStatusAndOutputWithTimeout( cmd, timeout_retry.CurrentTimeoutThread().GetRemainingTime()) if exit_code != 0: @@ -62,7 +63,7 @@ if check_error and output[:len('error:')] == 'error:': raise device_errors.AdbCommandFailedError(arg_list, output) return output - # pylint: enable=W0613 + # pylint: enable=unused-argument def _DeviceAdbCmd(self, arg_list, timeout, retries, check_error=True): """Runs an adb command on the device associated with this object.
diff --git a/build/android/pylib/device/commands/install_commands.py b/build/android/pylib/device/commands/install_commands.py index 35b11e3..58c56cc 100644 --- a/build/android/pylib/device/commands/install_commands.py +++ b/build/android/pylib/device/commands/install_commands.py
@@ -41,7 +41,7 @@ shell_command = _SHELL_COMMAND_FORMAT % ( constants.TEST_EXECUTABLE_DIR, main_class) shell_file = '%s/%s' % (BIN_DIR, command) - device.WriteTextFile(shell_file, shell_command) + device.WriteFile(shell_file, shell_command) device.RunShellCommand( ['chmod', '755', shell_file], check_return=True)
diff --git a/build/android/pylib/device/decorators_test.py b/build/android/pylib/device/decorators_test.py index 1ae8cb9..b75618b 100644 --- a/build/android/pylib/device/decorators_test.py +++ b/build/android/pylib/device/decorators_test.py
@@ -280,7 +280,7 @@ self.function_call_counters['alwaysRaisesCommandFailedError'] += 1 raise device_errors.CommandFailedError('testCommand failed') - # pylint: disable=R0201 + # pylint: disable=no-self-use @decorators.WithTimeoutAndRetriesFromInstance( 'default_timeout', 'default_retries') @@ -298,7 +298,7 @@ retries=None): raise exception - # pylint: enable=R0201 + # pylint: enable=no-self-use def testMethodDecoratorDoesTimeout(self):
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py index 334b74c..845d580 100644 --- a/build/android/pylib/device/device_utils.py +++ b/build/android/pylib/device/device_utils.py
@@ -24,7 +24,9 @@ from pylib.device import device_errors from pylib.device.commands import install_commands from pylib.utils import apk_helper +from pylib.utils import device_temp_file from pylib.utils import host_utils +from pylib.utils import md5sum from pylib.utils import parallelizer from pylib.utils import timeout_retry @@ -92,8 +94,8 @@ self._default_timeout = default_timeout self._default_retries = default_retries self._cache = {} - assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) - assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) + assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR) + assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR) @decorators.WithTimeoutAndRetriesFromInstance() def IsOnline(self, timeout=None, retries=None): @@ -429,13 +431,14 @@ if not isinstance(cmd, basestring): cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) - if as_root and self.NeedsSU(): - cmd = 'su -c %s' % cmd if env: env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) cmd = '%s %s' % (env, cmd) if cwd: cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) + if as_root and self.NeedsSU(): + # "su -c sh -c" allows using shell features in |cmd| + cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd) if timeout is None: timeout = self._default_timeout @@ -699,12 +702,13 @@ if not real_device_path: return [(host_path, device_path)] - # TODO(jbudorick): Move the md5 logic up into DeviceUtils or base - # this function on mtime. - # pylint: disable=W0212 - host_hash_tuples, device_hash_tuples = self.old_interface._RunMd5Sum( - real_host_path, real_device_path) - # pylint: enable=W0212 + host_hash_tuples = md5sum.CalculateHostMd5Sums([real_host_path]) + device_paths_to_md5 = ( + real_device_path if os.path.isfile(real_host_path) + else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path)) + for _, p in host_hash_tuples)) + device_hash_tuples = md5sum.CalculateDeviceMd5Sums( + device_paths_to_md5, self) if os.path.isfile(host_path): if (not device_hash_tuples @@ -765,7 +769,7 @@ else: zip_time = 0 transfer_time = byte_count / TRANSFER_RATE - return (adb_call_time + adb_push_setup_time + zip_time + transfer_time) + return adb_call_time + adb_push_setup_time + zip_time + transfer_time def _PushChangedFilesIndividually(self, files): for h, d in files: @@ -882,16 +886,19 @@ return self.old_interface.GetFileContents(device_path) @decorators.WithTimeoutAndRetriesFromInstance() - def WriteFile(self, device_path, contents, as_root=False, timeout=None, - retries=None): + def WriteFile(self, device_path, contents, as_root=False, force_push=False, + timeout=None, retries=None): """Writes |contents| to a file on the device. Args: device_path: A string containing the absolute path to the file to write - on the device. + on the device. contents: A string containing the data to write to the device. as_root: A boolean indicating whether the write should be executed with - root privileges. + root privileges (if available). + force_push: A boolean indicating whether to force the operation to be + performed by pushing a file to the device. The default is, when the + contents are short, to pass the contents using a shell script instead. timeout: timeout in seconds retries: number of retries @@ -900,39 +907,24 @@ CommandTimeoutError on timeout. DeviceUnreachableError on missing device. """ - if as_root: - if not self.old_interface.CanAccessProtectedFileContents(): - raise device_errors.CommandFailedError( - 'Cannot write to %s with root privileges.' % device_path) - self.old_interface.SetProtectedFileContents(device_path, contents) + if len(contents) < 512 and not force_push: + cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents), + cmd_helper.SingleQuote(device_path)) + self.RunShellCommand(cmd, as_root=as_root, check_return=True) else: - self.old_interface.SetFileContents(device_path, contents) - - @decorators.WithTimeoutAndRetriesFromInstance() - def WriteTextFile(self, device_path, text, as_root=False, timeout=None, - retries=None): - """Writes |text| to a file on the device. - - Assuming that |text| is a small string, this is typically more efficient - than |WriteFile|, as no files are pushed into the device. - - Args: - device_path: A string containing the absolute path to the file to write - on the device. - text: A short string of text to write to the file on the device. - as_root: A boolean indicating whether the write should be executed with - root privileges. - timeout: timeout in seconds - retries: number of retries - - Raises: - CommandFailedError if the file could not be written on the device. - CommandTimeoutError on timeout. - DeviceUnreachableError on missing device. - """ - cmd = 'echo %s > %s' % (cmd_helper.SingleQuote(text), - cmd_helper.SingleQuote(device_path)) - self.RunShellCommand(cmd, as_root=as_root, check_return=True) + with tempfile.NamedTemporaryFile() as host_temp: + host_temp.write(contents) + host_temp.flush() + if as_root and self.NeedsSU(): + with device_temp_file.DeviceTempFile(self) as device_temp: + self.adb.Push(host_temp.name, device_temp.name) + # Here we need 'cp' rather than 'mv' because the temp and + # destination files might be on different file systems (e.g. + # on internal storage and an external sd card) + self.RunShellCommand(['cp', device_temp.name, device_path], + as_root=True, check_return=True) + else: + self.adb.Push(host_temp.name, device_path) @decorators.WithTimeoutAndRetriesFromInstance() def Ls(self, device_path, timeout=None, retries=None):
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py index 65547d4..8d78b2d 100755 --- a/build/android/pylib/device/device_utils_test.py +++ b/build/android/pylib/device/device_utils_test.py
@@ -67,6 +67,19 @@ self.assertIsNone(d.old_interface.GetDevice()) +class MockTempFile(object): + + def __init__(self, name='/tmp/some/file'): + self.file = mock.MagicMock(spec=file) + self.file.name = name + + def __enter__(self): + return self.file + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + class _PatchedFunction(object): def __init__(self, patched=None, mocked=None): self.patched = patched @@ -215,9 +228,14 @@ return type(self).AndroidCommandsCalls(self, cmd_ret, comp) def setUp(self): + self._get_adb_path_patch = mock.patch('pylib.constants.GetAdbPath', + mock.Mock(return_value='adb')) + self._get_adb_path_patch.start() self.device = device_utils.DeviceUtils( '0123456789abcdef', default_timeout=1, default_retries=0) + def tearDown(self): + self._get_adb_path_patch.stop() class DeviceUtilsNewImplTest(mock_calls.TestCase): @@ -497,9 +515,6 @@ def mockGetFilesChanged(host_path, device_path, ignore_filenames): return [(host_path, device_path)] - # Pylint raises a false positive "operator not preceded by a space" - # warning below. - # pylint: disable=C0322 with mock.patch('os.path.isfile', return_value=True), ( mock.patch('os.path.exists', return_value=True)), ( mock.patch('pylib.utils.apk_helper.GetPackageName', @@ -508,7 +523,6 @@ return_value='/fake/test/out')), ( mock.patch('pylib.android_commands.AndroidCommands.GetFilesChanged', side_effect=mockGetFilesChanged)): - # pylint: enable=C0322 with self.assertCallsSequence([ ("adb -s 0123456789abcdef shell 'pm path this.is.a.test.package'", 'package:/fake/data/app/this.is.a.test.package.apk\r\n'), @@ -523,9 +537,6 @@ def mockGetFilesChanged(host_path, device_path, ignore_filenames): return [(host_path, device_path)] - # Pylint raises a false positive "operator not preceded by a space" - # warning below. - # pylint: disable=C0322 with mock.patch('os.path.isfile', return_value=True), ( mock.patch('pylib.utils.apk_helper.GetPackageName', return_value='this.is.a.test.package')), ( @@ -533,7 +544,6 @@ return_value='/fake/test/out')), ( mock.patch('pylib.android_commands.AndroidCommands.GetFilesChanged', side_effect=mockGetFilesChanged)): - # pylint: enable=C0322 with self.assertCallsSequence([ ("adb -s 0123456789abcdef shell 'pm path this.is.a.test.package'", 'package:/fake/data/app/this.is.a.test.package.apk\r\n'), @@ -614,7 +624,7 @@ def testRunShellCommand_withSu(self): with self.assertCalls( (self.call.device.NeedsSU(), True), - (self.call.adb.Shell('su -c setprop service.adb.root 0'), '')): + (self.call.adb.Shell("su -c sh -c 'setprop service.adb.root 0'"), '')): self.device.RunShellCommand('setprop service.adb.root 0', as_root=True) def testRunShellCommand_manyLines(self): @@ -714,7 +724,7 @@ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n' 'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'), (self.call.device.NeedsSU(), True), - (self.call.adb.Shell('su -c kill -9 1234'), '')): + (self.call.adb.Shell("su -c sh -c 'kill -9 1234'"), '')): self.assertEquals(1, self.device.KillAll('some.process', as_root=True)) @@ -1190,134 +1200,67 @@ as_root=True) -class DeviceUtilsWriteFileTest(DeviceUtilsOldImplTest): +class DeviceUtilsWriteFileTest(DeviceUtilsNewImplTest): - def testWriteFile_basic(self): - mock_file = mock.MagicMock(spec=file) - mock_file.name = '/tmp/file/to.be.pushed' - mock_file.__enter__.return_value = mock_file - with mock.patch('tempfile.NamedTemporaryFile', - return_value=mock_file): - with self.assertCalls( - 'adb -s 0123456789abcdef push ' - '/tmp/file/to.be.pushed /test/file/written.to.device', - '100 B/s (100 bytes in 1.000s)\r\n'): - self.device.WriteFile('/test/file/written.to.device', - 'new test file contents') - mock_file.write.assert_called_once_with('new test file contents') + def testWriteFile_withPush(self): + tmp_host = MockTempFile('/tmp/file/on.host') + contents = 'some large contents ' * 26 # 20 * 26 = 520 chars + with self.assertCalls( + (mock.call.tempfile.NamedTemporaryFile(), tmp_host), + self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file')): + self.device.WriteFile('/path/to/device/file', contents) + tmp_host.file.write.assert_called_once_with(contents) - def testWriteFile_asRoot_withRoot(self): - self.device.old_interface._external_storage = '/fake/storage/path' - self.device.old_interface._privileged_command_runner = ( - self.device.old_interface.RunShellCommand) - self.device.old_interface._protected_file_access_method_initialized = True + def testWriteFile_withPushForced(self): + tmp_host = MockTempFile('/tmp/file/on.host') + contents = 'tiny contents' + with self.assertCalls( + (mock.call.tempfile.NamedTemporaryFile(), tmp_host), + self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file')): + self.device.WriteFile('/path/to/device/file', contents, force_push=True) + tmp_host.file.write.assert_called_once_with(contents) - mock_file = mock.MagicMock(spec=file) - mock_file.name = '/tmp/file/to.be.pushed' - mock_file.__enter__.return_value = mock_file - with mock.patch('tempfile.NamedTemporaryFile', - return_value=mock_file): - with self.assertCallsSequence( - cmd_ret=[ - # Create temporary contents file - (r"adb -s 0123456789abcdef shell " - "'test -e \"/fake/storage/path/temp_file-\d+-\d+\"; " - "echo \$\?'", - '1\r\n'), - # Create temporary script file - (r"adb -s 0123456789abcdef shell " - "'test -e \"/fake/storage/path/temp_file-\d+-\d+\.sh\"; " - "echo \$\?'", - '1\r\n'), - # Set contents file - (r'adb -s 0123456789abcdef push /tmp/file/to\.be\.pushed ' - '/fake/storage/path/temp_file-\d+\d+', - '100 B/s (100 bytes in 1.000s)\r\n'), - # Set script file - (r'adb -s 0123456789abcdef push /tmp/file/to\.be\.pushed ' - '/fake/storage/path/temp_file-\d+\d+', - '100 B/s (100 bytes in 1.000s)\r\n'), - # Call script - (r"adb -s 0123456789abcdef shell " - "'sh /fake/storage/path/temp_file-\d+-\d+\.sh'", ''), - # Remove device temporaries - (r"adb -s 0123456789abcdef shell " - "'rm /fake/storage/path/temp_file-\d+-\d+\.sh'", ''), - (r"adb -s 0123456789abcdef shell " - "'rm /fake/storage/path/temp_file-\d+-\d+'", '')], - comp=re.match): - self.device.WriteFile('/test/file/written.to.device', - 'new test file contents', as_root=True) + def testWriteFile_withPushAndSU(self): + tmp_host = MockTempFile('/tmp/file/on.host') + contents = 'some large contents ' * 26 # 20 * 26 = 520 chars + with self.assertCalls( + (mock.call.tempfile.NamedTemporaryFile(), tmp_host), + (self.call.device.NeedsSU(), True), + (mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.device), + MockTempFile('/external/path/tmp/on.device')), + self.call.adb.Push('/tmp/file/on.host', '/external/path/tmp/on.device'), + self.call.device.RunShellCommand( + ['cp', '/external/path/tmp/on.device', '/path/to/device/file'], + as_root=True, check_return=True)): + self.device.WriteFile('/path/to/device/file', contents, as_root=True) + tmp_host.file.write.assert_called_once_with(contents) - def testWriteFile_asRoot_withSu(self): - self.device.old_interface._external_storage = '/fake/storage/path' - self.device.old_interface._privileged_command_runner = ( - self.device.old_interface.RunShellCommandWithSU) - self.device.old_interface._protected_file_access_method_initialized = True + def testWriteFile_withPush_rejected(self): + tmp_host = MockTempFile('/tmp/file/on.host') + contents = 'some large contents ' * 26 # 20 * 26 = 520 chars + with self.assertCalls( + (mock.call.tempfile.NamedTemporaryFile(), tmp_host), + (self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file'), + self.CommandError())): + with self.assertRaises(device_errors.CommandFailedError): + self.device.WriteFile('/path/to/device/file', contents) - mock_file = mock.MagicMock(spec=file) - mock_file.name = '/tmp/file/to.be.pushed' - mock_file.__enter__.return_value = mock_file - with mock.patch('tempfile.NamedTemporaryFile', - return_value=mock_file): - with self.assertCallsSequence( - cmd_ret=[ - # Create temporary contents file - (r"adb -s 0123456789abcdef shell " - "'test -e \"/fake/storage/path/temp_file-\d+-\d+\"; " - "echo \$\?'", - '1\r\n'), - # Create temporary script file - (r"adb -s 0123456789abcdef shell " - "'test -e \"/fake/storage/path/temp_file-\d+-\d+\.sh\"; " - "echo \$\?'", - '1\r\n'), - # Set contents file - (r'adb -s 0123456789abcdef push /tmp/file/to\.be\.pushed ' - '/fake/storage/path/temp_file-\d+\d+', - '100 B/s (100 bytes in 1.000s)\r\n'), - # Set script file - (r'adb -s 0123456789abcdef push /tmp/file/to\.be\.pushed ' - '/fake/storage/path/temp_file-\d+\d+', - '100 B/s (100 bytes in 1.000s)\r\n'), - # Call script - (r"adb -s 0123456789abcdef shell " - "'su -c sh /fake/storage/path/temp_file-\d+-\d+\.sh'", ''), - # Remove device temporaries - (r"adb -s 0123456789abcdef shell " - "'rm /fake/storage/path/temp_file-\d+-\d+\.sh'", ''), - (r"adb -s 0123456789abcdef shell " - "'rm /fake/storage/path/temp_file-\d+-\d+'", '')], - comp=re.match): - self.device.WriteFile('/test/file/written.to.device', - 'new test file contents', as_root=True) + def testWriteFile_withEcho(self): + with self.assertCall(self.call.adb.Shell( + "echo -n the.contents > /test/file/to.write"), ''): + self.device.WriteFile('/test/file/to.write', 'the.contents') - def testWriteFile_asRoot_rejected(self): - self.device.old_interface._privileged_command_runner = None - self.device.old_interface._protected_file_access_method_initialized = True - with self.assertRaises(device_errors.CommandFailedError): - self.device.WriteFile('/test/file/no.permissions.to.write', - 'new test file contents', as_root=True) + def testWriteFile_withEchoAndQuotes(self): + with self.assertCall(self.call.adb.Shell( + "echo -n 'the contents' > '/test/file/to write'"), ''): + self.device.WriteFile('/test/file/to write', 'the contents') - -class DeviceUtilsWriteTextFileTest(DeviceUtilsNewImplTest): - - def testWriteTextFileTest_basic(self): - with self.assertCall( - self.call.adb.Shell('echo some.string > /test/file/to.write'), ''): - self.device.WriteTextFile('/test/file/to.write', 'some.string') - - def testWriteTextFileTest_quoted(self): - with self.assertCall( - self.call.adb.Shell("echo 'some other string' > '/test/file/to write'"), - ''): - self.device.WriteTextFile('/test/file/to write', 'some other string') - - def testWriteTextFileTest_withSU(self): + def testWriteFile_withEchoAndSU(self): with self.assertCalls( (self.call.device.NeedsSU(), True), - (self.call.adb.Shell('su -c echo string > /test/file'), '')): - self.device.WriteTextFile('/test/file', 'string', as_root=True) + (self.call.adb.Shell("su -c sh -c 'echo -n contents > /test/file'"), + '')): + self.device.WriteFile('/test/file', 'contents', as_root=True) class DeviceUtilsLsTest(DeviceUtilsOldImplTest):
diff --git a/build/android/pylib/device_settings.py b/build/android/pylib/device_settings.py index 4050694..0580fcf 100644 --- a/build/android/pylib/device_settings.py +++ b/build/android/pylib/device_settings.py
@@ -8,6 +8,8 @@ from pylib import content_settings _LOCK_SCREEN_SETTINGS_PATH = '/data/system/locksettings.db' +_ALTERNATE_LOCK_SCREEN_SETTINGS_PATH = ( + '/data/data/com.android.providers.settings/databases/settings.db') PASSWORD_QUALITY_UNSPECIFIED = '0' @@ -66,16 +68,26 @@ Raises: Exception if the setting was not properly set. """ - if (not device.old_interface.FileExistsOnDevice(_LOCK_SCREEN_SETTINGS_PATH) or - device.GetProp('ro.build.type') != 'userdebug'): + if device.GetProp('ro.build.type') != 'userdebug': + logging.warning('Unable to disable lockscreen on user builds.') return - db = _LOCK_SCREEN_SETTINGS_PATH - locksettings = [('locksettings', 'lockscreen.disabled', '1'), - ('locksettings', 'lockscreen.password_type', - PASSWORD_QUALITY_UNSPECIFIED), - ('locksettings', 'lockscreen.password_type_alternate', - PASSWORD_QUALITY_UNSPECIFIED)] + def get_lock_settings(table): + return [(table, 'lockscreen.disabled', '1'), + (table, 'lockscreen.password_type', PASSWORD_QUALITY_UNSPECIFIED), + (table, 'lockscreen.password_type_alternate', + PASSWORD_QUALITY_UNSPECIFIED)] + + if device.FileExists(_LOCK_SCREEN_SETTINGS_PATH): + db = _LOCK_SCREEN_SETTINGS_PATH + locksettings = get_lock_settings('locksettings') + elif device.FileExists(_ALTERNATE_LOCK_SCREEN_SETTINGS_PATH): + db = _ALTERNATE_LOCK_SCREEN_SETTINGS_PATH + locksettings = get_lock_settings('secure') + get_lock_settings('system') + else: + logging.warning('Unable to find database file to set lock screen settings.') + return + for table, key, value in locksettings: # Set the lockscreen setting for default user '0' columns = ['name', 'user', 'value'] @@ -91,9 +103,10 @@ 'columns': ', '.join(columns), 'values': ', '.join(["'%s'" % value for value in values]) } - output_msg = device.RunShellCommand('sqlite3 %s "%s"' % (db, cmd)) + output_msg = device.RunShellCommand('sqlite3 %s "%s"' % (db, cmd), + as_root=True) if output_msg: - print ' '.join(output_msg) + logging.info(' '.join(output_msg)) ENABLE_LOCATION_SETTINGS = [
diff --git a/build/android/pylib/gtest/filter/net_unittests_disabled b/build/android/pylib/gtest/filter/net_unittests_disabled index 28e1db1..2632e7c 100644 --- a/build/android/pylib/gtest/filter/net_unittests_disabled +++ b/build/android/pylib/gtest/filter/net_unittests_disabled
@@ -7,7 +7,6 @@ SSLServerSocketTest.Handshake PythonUtils.PythonRunTime -URLRequestTestHTTP.HTTPSToHTTPRedirectNoRefererTest VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/0 VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/1 VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/2 @@ -26,6 +25,13 @@ VerifyRoot/CertVerifyProcWeakDigestTest.Verify/0 VerifyRoot/CertVerifyProcWeakDigestTest.Verify/1 VerifyRoot/CertVerifyProcWeakDigestTest.Verify/2 + +# Can't spin up more than one SpawnedTestServer on Android. +URLRequestTestReferrerPolicy.HTTPToCrossOriginHTTP +URLRequestTestReferrerPolicy.HTTPSToCrossOriginHTTPS +URLRequestTestReferrerPolicy.HTTPToHTTPS +URLRequestTestReferrerPolicy.HTTPSToHTTP + # Fail only on bots. HttpCache.RangeGET_Cancel HttpCache.RangeGET_Cancel2
diff --git a/build/android/pylib/gtest/gtest_config.py b/build/android/pylib/gtest/gtest_config.py index e671e0a..0cb8b35 100644 --- a/build/android/pylib/gtest/gtest_config.py +++ b/build/android/pylib/gtest/gtest_config.py
@@ -11,6 +11,10 @@ 'devtools_bridge_tests', ] +TELEMETRY_EXPERIMENTAL_TEST_SUITES = [ + 'telemetry_unittests', +] + # Do not modify this list without approval of an android owner. # This list determines which suites are run by default, both for local # testing and on android trybots running on commit-queue.
diff --git a/build/android/pylib/gtest/setup.py b/build/android/pylib/gtest/setup.py index e3df9c7..72c4b05 100644 --- a/build/android/pylib/gtest/setup.py +++ b/build/android/pylib/gtest/setup.py
@@ -10,15 +10,14 @@ import sys from pylib import constants -from pylib import valgrind_tools +from pylib.base import base_setup from pylib.base import base_test_result from pylib.base import test_dispatcher from pylib.device import device_utils from pylib.gtest import test_package_apk from pylib.gtest import test_package_exe from pylib.gtest import test_runner -from pylib.utils import isolator sys.path.insert(0, os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', @@ -26,7 +25,7 @@ import unittest_util # pylint: disable=F0401 -_ISOLATE_FILE_PATHS = { +ISOLATE_FILE_PATHS = { 'base_unittests': 'base/base_unittests.isolate', 'blink_heap_unittests': 'third_party/WebKit/Source/platform/heap/BlinkHeapUnitTests.isolate', @@ -48,7 +47,7 @@ # Used for filtering large data deps at a finer grain than what's allowed in # isolate files since pushing deps to devices is expensive. # Wildcards are allowed. -_DEPS_EXCLUSION_LIST = [ +DEPS_EXCLUSION_LIST = [ 'chrome/test/data/extensions/api_test', 'chrome/test/data/extensions/secure_shell', 'chrome/test/data/firefox*', @@ -68,43 +67,6 @@ ] -def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None): - """Generate the dependency dir for the test suite using isolate. - - Args: - suite_name: Name of the test suite (e.g. base_unittests). - isolate_file_path: .isolate file path to use. If there is a default .isolate - file path for the suite_name, this will override it. - """ - if isolate_file_path: - if os.path.isabs(isolate_file_path): - isolate_abs_path = isolate_file_path - else: - isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, - isolate_file_path) - else: - isolate_rel_path = _ISOLATE_FILE_PATHS.get(suite_name) - if not isolate_rel_path: - logging.info('Did not find an isolate file for the test suite.') - return - isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, isolate_rel_path) - - isolated_abs_path = os.path.join( - constants.GetOutDirectory(), '%s.isolated' % suite_name) - assert os.path.exists(isolate_abs_path), 'Cannot find %s' % isolate_abs_path - - i = isolator.Isolator(constants.ISOLATE_DEPS_DIR) - i.Clear() - i.Remap(isolate_abs_path, isolated_abs_path) - # We're relying on the fact that timestamps are preserved - # by the remap command (hardlinked). Otherwise, all the data - # will be pushed to the device once we move to using time diff - # instead of md5sum. Perform a sanity check here. - i.VerifyHardlinks() - i.PurgeExcluded(_DEPS_EXCLUSION_LIST) - i.MoveOutputDeps() - - def _GetDisabledTestsFilterFromFile(suite_name): """Returns a gtest filter based on the *_disabled file. @@ -218,19 +180,6 @@ return tests -def PushDataDeps(device, test_options, test_package): - valgrind_tools.PushFilesForTool(test_options.tool, device) - if os.path.exists(constants.ISOLATE_DEPS_DIR): - device_dir = ( - constants.TEST_EXECUTABLE_DIR - if test_package.suite_name == 'breakpad_unittests' - else device.GetExternalStoragePath()) - device.PushChangedFiles([ - (os.path.join(constants.ISOLATE_DEPS_DIR, p), - '%s/%s' % (device_dir, p)) - for p in os.listdir(constants.ISOLATE_DEPS_DIR)]) - - def Setup(test_options, devices): """Create the test runner factory and tests. @@ -255,11 +204,16 @@ test_package = exe_test_package logging.warning('Found target %s', test_package.suite_path) - _GenerateDepsDirUsingIsolate(test_options.suite_name, - test_options.isolate_file_path) - - device_utils.DeviceUtils.parallel(devices).pMap( - PushDataDeps, test_options, test_package) + base_setup.GenerateDepsDirUsingIsolate(test_options.suite_name, + test_options.isolate_file_path, + ISOLATE_FILE_PATHS, + DEPS_EXCLUSION_LIST) + def push_data_deps_to_device_dir(device): + device_dir = (constants.TEST_EXECUTABLE_DIR + if test_package.suite_name == 'breakpad_unittests' + else device.GetExternalStoragePath()) + base_setup.PushDataDeps(device, device_dir, test_options) + device_utils.DeviceUtils.parallel(devices).pMap(push_data_deps_to_device_dir) tests = _GetTests(test_options, test_package, devices)
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py index 66feea6..fa38c4f 100644 --- a/build/android/pylib/gtest/test_runner.py +++ b/build/android/pylib/gtest/test_runner.py
@@ -78,16 +78,16 @@ results = base_test_result.TestRunResults() # Test case statuses. - re_run = re.compile('\[ RUN \] ?(.*)\r\n') - re_fail = re.compile('\[ FAILED \] ?(.*?)( \((\d+) ms\))?\r\r\n') - re_ok = re.compile('\[ OK \] ?(.*?)( \((\d+) ms\))?\r\r\n') + re_run = re.compile('\\[ RUN \\] ?(.*)\r\n') + re_fail = re.compile('\\[ FAILED \\] ?(.*?)( \\((\\d+) ms\\))?\r\r\n') + re_ok = re.compile('\\[ OK \\] ?(.*?)( \\((\\d+) ms\\))?\r\r\n') # Test run statuses. - re_passed = re.compile('\[ PASSED \] ?(.*)\r\n') - re_runner_fail = re.compile('\[ RUNNER_FAILED \] ?(.*)\r\n') + re_passed = re.compile('\\[ PASSED \\] ?(.*)\r\n') + re_runner_fail = re.compile('\\[ RUNNER_FAILED \\] ?(.*)\r\n') # Signal handlers are installed before starting tests # to output the CRASHED marker when a crash happens. - re_crash = re.compile('\[ CRASHED \](.*)\r\n') + re_crash = re.compile('\\[ CRASHED \\](.*)\r\n') log = '' try:
diff --git a/build/android/pylib/instrumentation/setup.py b/build/android/pylib/instrumentation/setup.py index 57286e2..8dacc3d 100644 --- a/build/android/pylib/instrumentation/setup.py +++ b/build/android/pylib/instrumentation/setup.py
@@ -7,11 +7,63 @@ import logging import os +from pylib import constants +from pylib import valgrind_tools + +from pylib.base import base_setup +from pylib.device import device_utils from pylib.instrumentation import test_package from pylib.instrumentation import test_runner +DEVICE_DATA_DIR = 'chrome/test/data' -def Setup(test_options): +ISOLATE_FILE_PATHS = { + 'AndroidWebViewTest': 'android_webview/android_webview_test_apk.isolate', + 'ChromeShellTest': 'chrome/chrome_shell_test_apk.isolate', + 'ContentShellTest': 'content/content_shell_test_apk.isolate', +} + +DEPS_EXCLUSION_LIST = [] + +# TODO(mikecase): Remove this function and the constant DEVICE_DATA_DIR +# once all data deps are pushed to the same location on the device. +def _PushExtraSuiteDataDeps(device, test_apk): + """Pushes some extra data files/dirs needed by some test suite. + + Args: + test_apk: The test suite basename for which to return file paths. + """ + if test_apk in ['ChromeTest', 'ContentShellTest']: + test_files = 'net/data/ssl/certificates' + host_device_file_tuple = [ + (os.path.join(constants.DIR_SOURCE_ROOT, test_files), + os.path.join(device.GetExternalStoragePath(), test_files))] + device.PushChangedFiles(host_device_file_tuple) + + +# TODO(mikecase): Remove this function once everything uses +# base_setup.PushDataDeps to push data deps to the device. +def _PushDataDeps(device, test_options): + valgrind_tools.PushFilesForTool(test_options.tool, device) + + host_device_file_tuples = [] + for dest_host_pair in test_options.test_data: + dst_src = dest_host_pair.split(':', 1) + dst_layer = dst_src[0] + host_src = dst_src[1] + host_test_files_path = os.path.join(constants.DIR_SOURCE_ROOT, host_src) + if os.path.exists(host_test_files_path): + host_device_file_tuples += [( + host_test_files_path, + '%s/%s/%s' % ( + device.GetExternalStoragePath(), + DEVICE_DATA_DIR, + dst_layer))] + if host_device_file_tuples: + device.PushChangedFiles(host_device_file_tuples) + + +def Setup(test_options, devices): """Create and return the test runner factory and tests. Args: @@ -34,6 +86,24 @@ if not tests: logging.error('No instrumentation tests to run with current args.') + if test_options.test_data: + device_utils.DeviceUtils.parallel(devices).pMap( + _PushDataDeps, test_options) + else: + base_setup.GenerateDepsDirUsingIsolate(test_options.test_apk, + test_options.isolate_file_path, + ISOLATE_FILE_PATHS, + DEPS_EXCLUSION_LIST) + def push_data_deps_to_device_dir(device): + device_dir = os.path.join(device.GetExternalStoragePath(), + DEVICE_DATA_DIR) + base_setup.PushDataDeps(device, device_dir, test_options) + device_utils.DeviceUtils.parallel(devices).pMap( + push_data_deps_to_device_dir) + + device_utils.DeviceUtils.parallel(devices).pMap( + _PushExtraSuiteDataDeps, test_options.test_apk) + def TestRunnerFactory(device, shard_index): return test_runner.TestRunner(test_options, device, shard_index, test_pkg)
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py index 7b97e59..4473810 100644 --- a/build/android/pylib/instrumentation/test_jar.py +++ b/build/android/pylib/instrumentation/test_jar.py
@@ -14,6 +14,7 @@ from pylib import cmd_helper from pylib import constants from pylib.device import device_utils +from pylib.utils import md5sum from pylib.utils import proguard sys.path.insert(0, @@ -55,16 +56,6 @@ if not self._GetCachedProguardData(): self._GetProguardData() - @staticmethod - def _CalculateMd5(path): - # TODO(jbudorick): Move MD5sum calculations out of here and - # AndroidCommands to their own module. - out = cmd_helper.GetCmdOutput( - [os.path.join(constants.GetOutDirectory(), - 'md5sum_bin_host'), - path]) - return out - def _GetCachedProguardData(self): if (os.path.exists(self._pickled_proguard_name) and (os.path.getmtime(self._pickled_proguard_name) > @@ -74,7 +65,7 @@ try: with open(self._pickled_proguard_name, 'r') as r: d = pickle.loads(r.read()) - jar_md5 = self._CalculateMd5(self._jar_path) + jar_md5 = md5sum.CalculateHostMd5Sums(self._jar_path)[0].hash if (d['JAR_MD5SUM'] == jar_md5 and d['VERSION'] == PICKLE_FORMAT_VERSION): self._test_methods = d['TEST_METHODS'] @@ -114,7 +105,7 @@ logging.info('Storing proguard output to %s', self._pickled_proguard_name) d = {'VERSION': PICKLE_FORMAT_VERSION, 'TEST_METHODS': self._test_methods, - 'JAR_MD5SUM': self._CalculateMd5(self._jar_path)} + 'JAR_MD5SUM': md5sum.CalculateHostMd5Sums(self._jar_path)[0].hash} with open(self._pickled_proguard_name, 'w') as f: f.write(pickle.dumps(d)) @@ -228,9 +219,8 @@ int(v) for v in device_utils.DeviceUtils.parallel().GetProp( 'ro.build.version.sdk').pGet(None)] - tests = filter( - lambda t: self._IsTestValidForSdkRange(t, min(sdk_versions)), - tests) + tests = [t for t in tests + if self._IsTestValidForSdkRange(t, min(sdk_versions))] return tests
diff --git a/build/android/pylib/instrumentation/test_options.py b/build/android/pylib/instrumentation/test_options.py index d6a56de..639ca86 100644 --- a/build/android/pylib/instrumentation/test_options.py +++ b/build/android/pylib/instrumentation/test_options.py
@@ -22,4 +22,5 @@ 'test_apk_jar_path', 'test_runner', 'test_support_apk_path', - 'device_flags']) + 'device_flags', + 'isolate_file_path'])
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py index f2808da..92d80f97 100644 --- a/build/android/pylib/instrumentation/test_runner.py +++ b/build/android/pylib/instrumentation/test_runner.py
@@ -27,32 +27,13 @@ _PERF_TEST_ANNOTATION = 'PerfTest' -def _GetDataFilesForTestSuite(suite_basename): - """Returns a list of data files/dirs needed by the test suite. - - Args: - suite_basename: The test suite basename for which to return file paths. - - Returns: - A list of test file and directory paths. - """ - test_files = [] - if suite_basename in ['ChromeTest', 'ContentShellTest']: - test_files += [ - 'net/data/ssl/certificates/', - ] - return test_files - - class TestRunner(base_test_runner.BaseTestRunner): """Responsible for running a series of tests connected to a single device.""" - _DEVICE_DATA_DIR = 'chrome/test/data' _DEVICE_COVERAGE_DIR = 'chrome/test/coverage' _HOSTMACHINE_PERF_OUTPUT_FILE = '/tmp/chrome-profile' _DEVICE_PERF_OUTPUT_SEARCH_PREFIX = (constants.DEVICE_PERF_OUTPUT_DIR + '/chrome-profile*') - _DEVICE_HAS_TEST_FILES = {} def __init__(self, test_options, device, shard_index, test_pkg, additional_flags=None): @@ -89,45 +70,6 @@ def InstallTestPackage(self): self.test_pkg.Install(self.device) - #override - def PushDataDeps(self): - # TODO(frankf): Implement a general approach for copying/installing - # once across test runners. - if TestRunner._DEVICE_HAS_TEST_FILES.get(self.device, False): - logging.warning('Already copied test files to device %s, skipping.', - str(self.device)) - return - - host_device_file_tuples = [] - test_data = _GetDataFilesForTestSuite(self.test_pkg.GetApkName()) - if test_data: - # Make sure SD card is ready. - self.device.WaitUntilFullyBooted(timeout=20) - host_device_file_tuples += [ - (os.path.join(constants.DIR_SOURCE_ROOT, p), - os.path.join(self.device.GetExternalStoragePath(), p)) - for p in test_data] - - # TODO(frankf): Specify test data in this file as opposed to passing - # as command-line. - for dest_host_pair in self.options.test_data: - dst_src = dest_host_pair.split(':', 1) - dst_layer = dst_src[0] - host_src = dst_src[1] - host_test_files_path = os.path.join(constants.DIR_SOURCE_ROOT, - host_src) - if os.path.exists(host_test_files_path): - host_device_file_tuples += [( - host_test_files_path, - '%s/%s/%s' % ( - self.device.GetExternalStoragePath(), - TestRunner._DEVICE_DATA_DIR, - dst_layer))] - if host_device_file_tuples: - self.device.PushChangedFiles(host_device_file_tuples) - self.tool.CopyFiles(self.device) - TestRunner._DEVICE_HAS_TEST_FILES[str(self.device)] = True - def _GetInstrumentationArgs(self): ret = {} if self.options.wait_for_debugger: @@ -209,7 +151,7 @@ Whether the feature being tested is FirstRunExperience. """ annotations = self.test_pkg.GetTestAnnotations(test) - return ('FirstRunExperience' == annotations.get('Feature', None)) + return 'FirstRunExperience' == annotations.get('Feature', None) def _IsPerfTest(self, test): """Determines whether a test is a performance test. @@ -276,7 +218,8 @@ # Wait and grab annotation data so we can figure out which traces to parse regex = self.device.old_interface.WaitForLogMatch( - re.compile('\*\*PERFANNOTATION\(' + raw_test_name + '\)\:(.*)'), None) + re.compile(r'\*\*PERFANNOTATION\(' + raw_test_name + r'\)\:(.*)'), + None) # If the test is set to run on a specific device type only (IE: only # tablet or phone) and it is being run on the wrong device, the test
diff --git a/build/android/pylib/linker/setup.py b/build/android/pylib/linker/setup.py index 72bb131..ebfac87 100644 --- a/build/android/pylib/linker/setup.py +++ b/build/android/pylib/linker/setup.py
@@ -25,13 +25,13 @@ test_cases = [ test_case.LinkerLibraryAddressTest, test_case.LinkerSharedRelroTest, - test_case.LinkerRandomizationTest ] + test_case.LinkerRandomizationTest] low_memory_modes = [False, True] all_tests = [t(is_low_memory=m) for t in test_cases for m in low_memory_modes] if options.test_filter: - all_test_names = [ test.qualified_name for test in all_tests ] + all_test_names = [test.qualified_name for test in all_tests] filtered_test_names = unittest_util.FilterTestNames(all_test_names, options.test_filter) all_tests = [t for t in all_tests \
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py index f64a58b..13f68cb 100644 --- a/build/android/pylib/linker/test_case.py +++ b/build/android/pylib/linker/test_case.py
@@ -59,15 +59,15 @@ # from the Java source file above. _RE_LINKER_BROWSER_CONFIG = re.compile( r'.*BROWSER_SHARED_RELRO_CONFIG\s+=\s+' + - 'BROWSER_SHARED_RELRO_CONFIG_(\S+)\s*;.*', + r'BROWSER_SHARED_RELRO_CONFIG_(\S+)\s*;.*', re.MULTILINE | re.DOTALL) # Logcat filters used during each test. Only the 'chromium' one is really # needed, but the logs are added to the TestResult in case of error, and # it is handy to have the 'chromium_android_linker' ones as well when # troubleshooting. -_LOGCAT_FILTERS = [ '*:s', 'chromium:v', 'chromium_android_linker:v' ] -#_LOGCAT_FILTERS = [ '*:v' ] ## DEBUG +_LOGCAT_FILTERS = ['*:s', 'chromium:v', 'chromium_android_linker:v'] +#_LOGCAT_FILTERS = ['*:v'] ## DEBUG # Regular expression used to match status lines in logcat. re_status_line = re.compile(r'(BROWSER|RENDERER)_LINKER_TEST: (FAIL|SUCCESS)')
diff --git a/build/android/pylib/linker/test_runner.py b/build/android/pylib/linker/test_runner.py index 35eff19..3680f83 100644 --- a/build/android/pylib/linker/test_runner.py +++ b/build/android/pylib/linker/test_runner.py
@@ -38,7 +38,7 @@ super(LinkerExceptionTestResult, self).__init__( test_name, base_test_result.ResultType.FAIL, - log = "%s %s" % (exc_type, log_msg)) + log="%s %s" % (exc_type, log_msg)) class LinkerTestRunner(base_test_runner.BaseTestRunner):
diff --git a/build/android/pylib/perf/perf_control.py b/build/android/pylib/perf/perf_control.py index ede1317..73cf95c 100644 --- a/build/android/pylib/perf/perf_control.py +++ b/build/android/pylib/perf/perf_control.py
@@ -10,9 +10,7 @@ class PerfControl(object): """Provides methods for setting the performance mode of a device.""" - _SCALING_GOVERNOR_FMT = ( - '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor') - _CPU_ONLINE_FMT = '/sys/devices/system/cpu/cpu%d/online' + _CPU_PATH = '/sys/devices/system/cpu' _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' def __init__(self, device): @@ -20,11 +18,12 @@ if isinstance(device, android_commands.AndroidCommands): device = device_utils.DeviceUtils(device) self._device = device - cpu_files = self._device.RunShellCommand( - 'ls -d /sys/devices/system/cpu/cpu[0-9]*') - self._num_cpu_cores = len(cpu_files) - assert self._num_cpu_cores > 0, 'Failed to detect CPUs.' - logging.info('Number of CPUs: %d', self._num_cpu_cores) + # this will raise an AdbShellCommandFailedError if no CPU files are found + self._cpu_files = self._device.RunShellCommand( + 'ls -d cpu[0-9]*', cwd=self._CPU_PATH, check_return=True, as_root=True) + assert self._cpu_files, 'Failed to detect CPUs.' + self._cpu_file_list = ' '.join(self._cpu_files) + logging.info('CPUs found: %s', self._cpu_file_list) self._have_mpdecision = self._device.FileExists('/system/bin/mpdecision') def SetHighPerfMode(self): @@ -84,22 +83,41 @@ self._SetScalingGovernorInternal(governor_mode) self._ForceAllCpusOnline(False) + def GetCpuInfo(self): + online = (output.rstrip() == '1' and status == 0 + for (_, output, status) in self._ForEachCpu('cat "$CPU/online"')) + governor = (output.rstrip() if status == 0 else None + for (_, output, status) + in self._ForEachCpu('cat "$CPU/cpufreq/scaling_governor"')) + return zip(self._cpu_files, online, governor) + + def _ForEachCpu(self, cmd): + script = '; '.join([ + 'for CPU in %s' % self._cpu_file_list, + 'do %s' % cmd, + 'echo -n "%~%$?%~%"', + 'done' + ]) + output = self._device.RunShellCommand( + script, cwd=self._CPU_PATH, check_return=True, as_root=True) + output = '\n'.join(output).split('%~%') + return zip(self._cpu_files, output[0::2], (int(c) for c in output[1::2])) + + def _WriteEachCpuFile(self, path, value): + results = self._ForEachCpu( + 'test -e "$CPU/{path}" && echo {value} > "$CPU/{path}"'.format( + path=path, value=value)) + cpus = ' '.join(cpu for (cpu, _, status) in results if status == 0) + if cpus: + logging.info('Successfully set %s to %r on: %s', path, value, cpus) + else: + logging.warning('Failed to set %s to %r on any cpus') + def _SetScalingGovernorInternal(self, value): - cpu_cores = ' '.join([str(x) for x in range(self._num_cpu_cores)]) - script = ('for CPU in %s; do\n' - ' FILE="/sys/devices/system/cpu/cpu$CPU/cpufreq/scaling_governor"\n' - ' test -e $FILE && echo %s > $FILE\n' - 'done\n') % (cpu_cores, value) - logging.info('Setting scaling governor mode: %s', value) - self._device.RunShellCommand(script, as_root=True) + self._WriteEachCpuFile('cpufreq/scaling_governor', value) def _SetScalingMaxFreq(self, value): - cpu_cores = ' '.join([str(x) for x in range(self._num_cpu_cores)]) - script = ('for CPU in %s; do\n' - ' FILE="/sys/devices/system/cpu/cpu$CPU/cpufreq/scaling_max_freq"\n' - ' test -e $FILE && echo %d > $FILE\n' - 'done\n') % (cpu_cores, value) - self._device.RunShellCommand(script, as_root=True) + self._WriteEachCpuFile('cpufreq/scaling_max_freq', '%d' % value) def _SetMaxGpuClock(self, value): self._device.WriteFile('/sys/class/kgsl/kgsl-3d0/max_gpuclk', @@ -107,14 +125,12 @@ as_root=True) def _AllCpusAreOnline(self): - for cpu in range(1, self._num_cpu_cores): - online_path = PerfControl._CPU_ONLINE_FMT % cpu - # TODO(epenner): Investigate why file may be missing - # (http://crbug.com/397118) - if not self._device.FileExists(online_path) or \ - self._device.ReadFile(online_path)[0] == '0': - return False - return True + results = self._ForEachCpu('cat "$CPU/online"') + # TODO(epenner): Investigate why file may be missing + # (http://crbug.com/397118) + return all(output.rstrip() == '1' and status == 0 + for (cpu, output, status) in results + if cpu != 'cpu0') def _ForceAllCpusOnline(self, force_online): """Enable all CPUs on a device. @@ -132,15 +148,10 @@ """ if self._have_mpdecision: script = 'stop mpdecision' if force_online else 'start mpdecision' - self._device.RunShellCommand(script, as_root=True) + self._device.RunShellCommand(script, check_return=True, as_root=True) if not self._have_mpdecision and not self._AllCpusAreOnline(): logging.warning('Unexpected cpu hot plugging detected.') - if not force_online: - return - - for cpu in range(self._num_cpu_cores): - online_path = PerfControl._CPU_ONLINE_FMT % cpu - self._device.WriteFile(online_path, '1', as_root=True) - + if force_online: + self._ForEachCpu('echo 1 > "$CPU/online"')
diff --git a/build/android/pylib/perf/perf_control_unittest.py b/build/android/pylib/perf/perf_control_unittest.py index aa31f68..dd7cb88 100644 --- a/build/android/pylib/perf/perf_control_unittest.py +++ b/build/android/pylib/perf/perf_control_unittest.py
@@ -27,13 +27,11 @@ perf = perf_control.PerfControl(self._device) try: perf.SetPerfProfilingMode() - for cpu in range(perf._num_cpu_cores): - path = perf_control.PerfControl._CPU_ONLINE_FMT % cpu - self.assertEquals('1', - self._device.ReadFile(path)[0]) - path = perf_control.PerfControl._SCALING_GOVERNOR_FMT % cpu - self.assertEquals('performance', - self._device.ReadFile(path)[0]) + cpu_info = perf.GetCpuInfo() + self.assertEquals(len(perf._cpu_files), len(cpu_info)) + for _, online, governor in cpu_info: + self.assertTrue(online) + self.assertEquals('performance', governor) finally: perf.SetDefaultPerfMode()
diff --git a/build/android/pylib/perf/surface_stats_collector.py b/build/android/pylib/perf/surface_stats_collector.py index a34d87d..499b0c6 100644 --- a/build/android/pylib/perf/surface_stats_collector.py +++ b/build/android/pylib/perf/surface_stats_collector.py
@@ -13,7 +13,7 @@ # Log marker containing SurfaceTexture timestamps. _SURFACE_TEXTURE_TIMESTAMPS_MESSAGE = 'SurfaceTexture update timestamps' -_SURFACE_TEXTURE_TIMESTAMP_RE = '\d+' +_SURFACE_TEXTURE_TIMESTAMP_RE = r'\d+' _MIN_NORMALIZED_FRAME_LENGTH = 0.5 @@ -90,8 +90,8 @@ def _GetNormalizedDeltas(data, refresh_period, min_normalized_delta=None): deltas = [t2 - t1 for t1, t2 in zip(data, data[1:])] if min_normalized_delta != None: - deltas = filter(lambda d: d / refresh_period >= min_normalized_delta, - deltas) + deltas = [d for d in deltas + if d / refresh_period >= min_normalized_delta] return (deltas, [delta / refresh_period for delta in deltas]) @staticmethod @@ -297,7 +297,7 @@ """ results = self._device.RunShellCommand('service call SurfaceFlinger 1013') assert len(results) == 1 - match = re.search('^Result: Parcel\((\w+)', results[0]) + match = re.search(r'^Result: Parcel\((\w+)', results[0]) cur_surface = 0 if match: try:
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py index b47a236..1ab9545 100644 --- a/build/android/pylib/uiautomator/test_runner.py +++ b/build/android/pylib/uiautomator/test_runner.py
@@ -40,7 +40,8 @@ test_apk_jar_path=None, test_runner=None, test_support_apk_path=None, - device_flags=None) + device_flags=None, + isolate_file_path=None) super(TestRunner, self).__init__(instrumentation_options, device, shard_index, test_pkg) @@ -56,15 +57,11 @@ self.test_pkg.Install(self.device) #override - def PushDataDeps(self): - pass - - #override def _RunTest(self, test, timeout): self.device.ClearApplicationState(self._package) if self.flags: annotations = self.test_pkg.GetTestAnnotations(test) - if ('FirstRunExperience' == annotations.get('Feature', None)): + if 'FirstRunExperience' == annotations.get('Feature', None): self.flags.RemoveFlags(['--disable-fre']) else: self.flags.AddFlags(['--disable-fre'])
diff --git a/build/android/pylib/utils/host_path_finder.py b/build/android/pylib/utils/host_path_finder.py index aea51a9..389ac43 100644 --- a/build/android/pylib/utils/host_path_finder.py +++ b/build/android/pylib/utils/host_path_finder.py
@@ -14,9 +14,8 @@ """ out_dir = os.path.join( constants.DIR_SOURCE_ROOT, os.environ.get('CHROMIUM_OUT_DIR', 'out')) - candidate_paths = map( - lambda build_type: os.path.join(out_dir, build_type, file_name), - ['Debug', 'Release']) + candidate_paths = [os.path.join(out_dir, build_type, file_name) + for build_type in ['Debug', 'Release']] candidate_paths = filter(os.path.exists, candidate_paths) candidate_paths = sorted(candidate_paths, key=os.path.getmtime, reverse=True) candidate_paths.append('')
diff --git a/build/android/pylib/utils/json_results_generator.py b/build/android/pylib/utils/json_results_generator.py index d40860d..e5c433d 100644 --- a/build/android/pylib/utils/json_results_generator.py +++ b/build/android/pylib/utils/json_results_generator.py
@@ -157,10 +157,10 @@ TIMES_MS_FILENAME = 'times_ms.json' INCREMENTAL_RESULTS_FILENAME = 'incremental_results.json' - # line too long pylint: disable=C0301 + # line too long pylint: disable=line-too-long URL_FOR_TEST_LIST_JSON = ( 'http://%s/testfile?builder=%s&name=%s&testlistjson=1&testtype=%s&master=%s') - # pylint: enable=C0301 + # pylint: enable=line-too-long def __init__(self, builder_name, build_name, build_number, results_file_base_path, builder_base_url, @@ -387,7 +387,7 @@ except urllib2.HTTPError, http_error: # A non-4xx status code means the bot is hosed for some reason # and we can't grab the results.json file off of it. - if (http_error.code < 400 and http_error.code >= 500): + if http_error.code < 400 and http_error.code >= 500: error = http_error except urllib2.URLError, url_error: error = url_error
diff --git a/build/android/pylib/utils/md5sum.py b/build/android/pylib/utils/md5sum.py new file mode 100644 index 0000000..8c10bb0 --- /dev/null +++ b/build/android/pylib/utils/md5sum.py
@@ -0,0 +1,72 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import collections +import logging +import os +import tempfile +import types + +from pylib import cmd_helper +from pylib import constants +from pylib.utils import device_temp_file + +HashAndPath = collections.namedtuple('HashAndPath', ['hash', 'path']) + +MD5SUM_DEVICE_LIB_PATH = '/data/local/tmp/md5sum/' +MD5SUM_DEVICE_BIN_PATH = MD5SUM_DEVICE_LIB_PATH + 'md5sum_bin' + +MD5SUM_DEVICE_SCRIPT_FORMAT = ( + 'test -f {path} -o -d {path} ' + '&& LD_LIBRARY_PATH={md5sum_lib} {md5sum_bin} {path}') + + +def CalculateHostMd5Sums(paths): + """Calculates the MD5 sum value for all items in |paths|. + + Args: + paths: A list of host paths to md5sum. + Returns: + A list of named tuples with 'hash' and 'path' attributes. + """ + if isinstance(paths, basestring): + paths = [paths] + + out = cmd_helper.GetCmdOutput( + [os.path.join(constants.GetOutDirectory(), 'md5sum_bin_host')] + + [p for p in paths]) + return [HashAndPath(*l.split(None, 1)) for l in out.splitlines()] + + +def CalculateDeviceMd5Sums(paths, device): + """Calculates the MD5 sum value for all items in |paths|. + + Args: + paths: A list of device paths to md5sum. + Returns: + A list of named tuples with 'hash' and 'path' attributes. + """ + if isinstance(paths, basestring): + paths = [paths] + + if not device.FileExists(MD5SUM_DEVICE_BIN_PATH): + device.adb.Push( + os.path.join(constants.GetOutDirectory(), 'md5sum_dist'), + MD5SUM_DEVICE_LIB_PATH) + + out = [] + with tempfile.NamedTemporaryFile() as md5sum_script_file: + with device_temp_file.DeviceTempFile(device) as md5sum_device_script_file: + md5sum_script = ( + MD5SUM_DEVICE_SCRIPT_FORMAT.format( + path=p, md5sum_lib=MD5SUM_DEVICE_LIB_PATH, + md5sum_bin=MD5SUM_DEVICE_BIN_PATH) + for p in paths) + md5sum_script_file.write('; '.join(md5sum_script)) + md5sum_script_file.flush() + device.adb.Push(md5sum_script_file.name, md5sum_device_script_file.name) + out = device.RunShellCommand(['sh', md5sum_device_script_file.name]) + + return [HashAndPath(*l.split(None, 1)) for l in out] +
diff --git a/build/android/pylib/utils/md5sum_test.py b/build/android/pylib/utils/md5sum_test.py new file mode 100755 index 0000000..6c689fb --- /dev/null +++ b/build/android/pylib/utils/md5sum_test.py
@@ -0,0 +1,183 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import sys +import unittest + +from pylib import cmd_helper +from pylib import constants +from pylib.utils import md5sum + +sys.path.append( + os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pymock')) +import mock + +TEST_OUT_DIR = os.path.join('test', 'out', 'directory') +HOST_MD5_EXECUTABLE = os.path.join(TEST_OUT_DIR, 'md5sum_bin_host') + +class Md5SumTest(unittest.TestCase): + + def setUp(self): + self._patchers = [ + mock.patch('pylib.constants.GetOutDirectory', + new=mock.Mock(return_value=TEST_OUT_DIR)), + ] + for p in self._patchers: + p.start() + + def tearDown(self): + for p in self._patchers: + p.stop() + + def testCalculateHostMd5Sums_singlePath(self): + test_path = '/test/host/file.dat' + mock_get_cmd_output = mock.Mock( + return_value='0123456789abcdeffedcba9876543210 /test/host/file.dat') + with mock.patch('pylib.cmd_helper.GetCmdOutput', new=mock_get_cmd_output): + out = md5sum.CalculateHostMd5Sums(test_path) + self.assertEquals(1, len(out)) + self.assertEquals('0123456789abcdeffedcba9876543210', out[0].hash) + self.assertEquals('/test/host/file.dat', out[0].path) + mock_get_cmd_output.assert_called_once_with( + [HOST_MD5_EXECUTABLE, '/test/host/file.dat']) + + def testCalculateHostMd5Sums_list(self): + test_paths = ['/test/host/file0.dat', '/test/host/file1.dat'] + mock_get_cmd_output = mock.Mock( + return_value='0123456789abcdeffedcba9876543210 /test/host/file0.dat\n' + '123456789abcdef00fedcba987654321 /test/host/file1.dat\n') + with mock.patch('pylib.cmd_helper.GetCmdOutput', new=mock_get_cmd_output): + out = md5sum.CalculateHostMd5Sums(test_paths) + self.assertEquals(2, len(out)) + self.assertEquals('0123456789abcdeffedcba9876543210', out[0].hash) + self.assertEquals('/test/host/file0.dat', out[0].path) + self.assertEquals('123456789abcdef00fedcba987654321', out[1].hash) + self.assertEquals('/test/host/file1.dat', out[1].path) + mock_get_cmd_output.assert_called_once_with( + [HOST_MD5_EXECUTABLE, '/test/host/file0.dat', + '/test/host/file1.dat']) + + def testCalculateHostMd5Sums_generator(self): + test_paths = ('/test/host/' + p for p in ['file0.dat', 'file1.dat']) + mock_get_cmd_output = mock.Mock( + return_value='0123456789abcdeffedcba9876543210 /test/host/file0.dat\n' + '123456789abcdef00fedcba987654321 /test/host/file1.dat\n') + with mock.patch('pylib.cmd_helper.GetCmdOutput', new=mock_get_cmd_output): + out = md5sum.CalculateHostMd5Sums(test_paths) + self.assertEquals(2, len(out)) + self.assertEquals('0123456789abcdeffedcba9876543210', out[0].hash) + self.assertEquals('/test/host/file0.dat', out[0].path) + self.assertEquals('123456789abcdef00fedcba987654321', out[1].hash) + self.assertEquals('/test/host/file1.dat', out[1].path) + mock_get_cmd_output.assert_called_once_with( + [HOST_MD5_EXECUTABLE, '/test/host/file0.dat', '/test/host/file1.dat']) + + def testCalculateDeviceMd5Sums_singlePath(self): + test_path = '/storage/emulated/legacy/test/file.dat' + + device = mock.NonCallableMock() + device.adb = mock.NonCallableMock() + device.adb.Push = mock.Mock() + device_md5sum_output = [ + '0123456789abcdeffedcba9876543210 ' + '/storage/emulated/legacy/test/file.dat', + ] + device.RunShellCommand = mock.Mock(return_value=device_md5sum_output) + + mock_temp_file = mock.mock_open() + mock_temp_file.return_value.name = '/tmp/test/script/file.sh' + + mock_device_temp_file = mock.mock_open() + mock_device_temp_file.return_value.name = ( + '/data/local/tmp/test/script/file.sh') + + with mock.patch('tempfile.NamedTemporaryFile', new=mock_temp_file), ( + mock.patch('pylib.utils.device_temp_file.DeviceTempFile', + new=mock_device_temp_file)): + out = md5sum.CalculateDeviceMd5Sums(test_path, device) + self.assertEquals(1, len(out)) + self.assertEquals('0123456789abcdeffedcba9876543210', out[0].hash) + self.assertEquals('/storage/emulated/legacy/test/file.dat', out[0].path) + device.adb.Push.assert_called_once_with( + '/tmp/test/script/file.sh', '/data/local/tmp/test/script/file.sh') + device.RunShellCommand.assert_called_once_with( + ['sh', '/data/local/tmp/test/script/file.sh']) + + def testCalculateDeviceMd5Sums_list(self): + test_path = ['/storage/emulated/legacy/test/file0.dat', + '/storage/emulated/legacy/test/file1.dat'] + device = mock.NonCallableMock() + device.adb = mock.NonCallableMock() + device.adb.Push = mock.Mock() + device_md5sum_output = [ + '0123456789abcdeffedcba9876543210 ' + '/storage/emulated/legacy/test/file0.dat', + '123456789abcdef00fedcba987654321 ' + '/storage/emulated/legacy/test/file1.dat', + ] + device.RunShellCommand = mock.Mock(return_value=device_md5sum_output) + + mock_temp_file = mock.mock_open() + mock_temp_file.return_value.name = '/tmp/test/script/file.sh' + + mock_device_temp_file = mock.mock_open() + mock_device_temp_file.return_value.name = ( + '/data/local/tmp/test/script/file.sh') + + with mock.patch('tempfile.NamedTemporaryFile', new=mock_temp_file), ( + mock.patch('pylib.utils.device_temp_file.DeviceTempFile', + new=mock_device_temp_file)): + out = md5sum.CalculateDeviceMd5Sums(test_path, device) + self.assertEquals(2, len(out)) + self.assertEquals('0123456789abcdeffedcba9876543210', out[0].hash) + self.assertEquals('/storage/emulated/legacy/test/file0.dat', out[0].path) + self.assertEquals('123456789abcdef00fedcba987654321', out[1].hash) + self.assertEquals('/storage/emulated/legacy/test/file1.dat', out[1].path) + device.adb.Push.assert_called_once_with( + '/tmp/test/script/file.sh', '/data/local/tmp/test/script/file.sh') + device.RunShellCommand.assert_called_once_with( + ['sh', '/data/local/tmp/test/script/file.sh']) + + def testCalculateDeviceMd5Sums_generator(self): + test_path = ('/storage/emulated/legacy/test/file%d.dat' % n + for n in xrange(0, 2)) + + device = mock.NonCallableMock() + device.adb = mock.NonCallableMock() + device.adb.Push = mock.Mock() + device_md5sum_output = [ + '0123456789abcdeffedcba9876543210 ' + '/storage/emulated/legacy/test/file0.dat', + '123456789abcdef00fedcba987654321 ' + '/storage/emulated/legacy/test/file1.dat', + ] + device.RunShellCommand = mock.Mock(return_value=device_md5sum_output) + + mock_temp_file = mock.mock_open() + mock_temp_file.return_value.name = '/tmp/test/script/file.sh' + + mock_device_temp_file = mock.mock_open() + mock_device_temp_file.return_value.name = ( + '/data/local/tmp/test/script/file.sh') + + with mock.patch('tempfile.NamedTemporaryFile', new=mock_temp_file), ( + mock.patch('pylib.utils.device_temp_file.DeviceTempFile', + new=mock_device_temp_file)): + out = md5sum.CalculateDeviceMd5Sums(test_path, device) + self.assertEquals(2, len(out)) + self.assertEquals('0123456789abcdeffedcba9876543210', out[0].hash) + self.assertEquals('/storage/emulated/legacy/test/file0.dat', out[0].path) + self.assertEquals('123456789abcdef00fedcba987654321', out[1].hash) + self.assertEquals('/storage/emulated/legacy/test/file1.dat', out[1].path) + device.adb.Push.assert_called_once_with( + '/tmp/test/script/file.sh', '/data/local/tmp/test/script/file.sh') + device.RunShellCommand.assert_called_once_with( + ['sh', '/data/local/tmp/test/script/file.sh']) + + +if __name__ == '__main__': + unittest.main(verbosity=2) +
diff --git a/build/android/pylib/utils/mock_calls.py b/build/android/pylib/utils/mock_calls.py old mode 100755 new mode 100644 index 1f9d8e3..b10ebc6 --- a/build/android/pylib/utils/mock_calls.py +++ b/build/android/pylib/utils/mock_calls.py
@@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/build/android/pylib/utils/parallelizer.py b/build/android/pylib/utils/parallelizer.py index 9323c21..9a85b54 100644 --- a/build/android/pylib/utils/parallelizer.py +++ b/build/android/pylib/utils/parallelizer.py
@@ -52,7 +52,7 @@ penalty. """ -# pylint: disable=W0613 +# pylint: disable=protected-access from pylib.utils import reraiser_thread from pylib.utils import watchdog_timer @@ -194,11 +194,11 @@ or '_assertNoShadow'. """ if isinstance(self._objs, reraiser_thread.ReraiserThreadGroup): - assert(not hasattr(self._objs, '_assertNoShadow')) - assert(not hasattr(self._objs, 'pGet')) + assert not hasattr(self._objs, '_assertNoShadow') + assert not hasattr(self._objs, attr_name) else: - assert(not any(hasattr(o, '_assertNoShadow') for o in self._objs)) - assert(not any(hasattr(o, 'pGet') for o in self._objs)) + assert not any(hasattr(o, '_assertNoShadow') for o in self._objs) + assert not any(hasattr(o, attr_name) for o in self._objs) class SyncParallelizer(Parallelizer):
diff --git a/build/android/pylib/utils/report_results.py b/build/android/pylib/utils/report_results.py index 9841dc6..8f81c95 100644 --- a/build/android/pylib/utils/report_results.py +++ b/build/android/pylib/utils/report_results.py
@@ -18,7 +18,7 @@ if not os.path.exists(log_file_path): os.mkdir(log_file_path) full_file_name = os.path.join( - log_file_path, re.sub('\W', '_', test_type).lower() + '.log') + log_file_path, re.sub(r'\W', '_', test_type).lower() + '.log') if not os.path.exists(full_file_name): with open(full_file_name, 'w') as log_file: print >> log_file, '\n%s results for %s build %s:' % (
diff --git a/build/android/rezip/RezipApk.java b/build/android/rezip/RezipApk.java index fcb0703..b4285cd 100644 --- a/build/android/rezip/RezipApk.java +++ b/build/android/rezip/RezipApk.java
@@ -39,8 +39,8 @@ // Files matching this pattern are not copied to the output when adding alignment. // When reordering and verifying the APK they are copied to the end of the file. private static Pattern sMetaFilePattern = - Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA)|com/android/otacert))|(" + - Pattern.quote(JarFile.MANIFEST_NAME) + ")$"); + Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA)|com/android/otacert))|(" + + Pattern.quote(JarFile.MANIFEST_NAME) + ")$"); // Pattern for matching a shared library in the APK private static Pattern sLibraryPattern = Pattern.compile("^lib/[^/]*/lib.*[.]so$"); @@ -48,12 +48,11 @@ private static Pattern sCrazyLinkerPattern = Pattern.compile("^lib/[^/]*/libchromium_android_linker.so$"); // Pattern for matching a crazy loaded shared library in the APK - private static Pattern sCrazyLibraryPattern = - Pattern.compile("^lib/[^/]*/crazy.lib.*[.]so$"); + private static Pattern sCrazyLibraryPattern = Pattern.compile("^lib/[^/]*/crazy.lib.*[.]so$"); private static boolean isLibraryFilename(String filename) { - return sLibraryPattern.matcher(filename).matches() && - !sCrazyLinkerPattern.matcher(filename).matches(); + return sLibraryPattern.matcher(filename).matches() + && !sCrazyLinkerPattern.matcher(filename).matches(); } private static boolean isCrazyLibraryFilename(String filename) { @@ -150,8 +149,7 @@ if (entry.isDirectory()) { continue; } - if (omitMetaFiles && - sMetaFilePattern.matcher(entry.getName()).matches()) { + if (omitMetaFiles && sMetaFilePattern.matcher(entry.getName()).matches()) { continue; } entries.add(entry); @@ -394,16 +392,12 @@ } private static void usage() { - System.err.println( - "Usage: prealignapk (addalignment|reorder) input.apk output.apk"); - System.err.println( - "\"crazy\" libraries are always inflated in the output"); + System.err.println("Usage: prealignapk (addalignment|reorder) input.apk output.apk"); + System.err.println("\"crazy\" libraries are always inflated in the output"); System.err.println( " renamealign - rename libraries with \"crazy.\" prefix and add alignment file"); - System.err.println( - " align - add alignment file"); - System.err.println( - " reorder - re-creates canonical ordering and checks alignment"); + System.err.println(" align - add alignment file"); + System.err.println(" reorder - re-creates canonical ordering and checks alignment"); System.exit(2); }
diff --git a/build/android/surface_stats.py b/build/android/surface_stats.py index 74bfdce..911dd2e 100755 --- a/build/android/surface_stats.py +++ b/build/android/surface_stats.py
@@ -13,6 +13,8 @@ import sys import time +from pylib.device import adb_wrapper +from pylib.device import device_errors from pylib.device import device_utils from pylib.perf import surface_stats_collector from pylib.utils import run_tests_helper @@ -98,7 +100,14 @@ options, _ = parser.parse_args(argv) run_tests_helper.SetLogLevel(options.verbose_count) - device = device_utils.DeviceUtils(options.device) + if options.device: + device = device_utils.DeviceUtils(options.device) + else: + devices = adb_wrapper.AdbWrapper.GetDevices() + if not devices: + raise device_errors.NoDevicesError + device = device_utils.DeviceUtils(devices[0]) + collector = surface_stats_collector.SurfaceStatsCollector(device) collector.DisableWarningAboutEmptyData()
diff --git a/build/android/symbolize.py b/build/android/symbolize.py index cb5d475..56d3b19 100755 --- a/build/android/symbolize.py +++ b/build/android/symbolize.py
@@ -24,8 +24,8 @@ # Sample output from base/debug/stack_trace_android.cc #00 0x693cd34f /path/to/some/libfoo.so+0x0007434f -TRACE_LINE = re.compile('(?P<frame>\#[0-9]+ 0x[0-9a-f]{8,8}) ' - '(?P<lib>[^+]+)\+0x(?P<addr>[0-9a-f]{8,8})') +TRACE_LINE = re.compile(r'(?P<frame>\#[0-9]+ 0x[0-9a-f]{8,8}) ' + r'(?P<lib>[^+]+)\+0x(?P<addr>[0-9a-f]{8,8})') class Symbolizer(object): def __init__(self, output):
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index d5c9b35..b483d2b 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -91,6 +91,9 @@ group.add_option('-e', '--environment', default='local', help=('Test environment to run in. Must be one of: %s' % ', '.join(constants.VALID_ENVIRONMENTS))) + group.add_option('--adb-path', + help=('Specify the absolute path of the adb binary that ' + 'should be used.')) option_parser.add_option_group(group) @@ -102,6 +105,12 @@ constants.SetBuildDirectory(options.build_directory) if options.output_directory: constants.SetOutputDirectort(options.output_directory) + if options.adb_path: + constants.SetAdbPath(options.adb_path) + # Some things such as Forwarder require ADB to be in the environment path. + adb_dir = os.path.dirname(constants.GetAdbPath()) + if adb_dir and adb_dir not in os.environ['PATH'].split(os.pathsep): + os.environ['PATH'] = adb_dir + os.pathsep + os.environ['PATH'] if options.environment not in constants.VALID_ENVIRONMENTS: error_func('--environment must be one of: %s' % ', '.join(constants.VALID_ENVIRONMENTS)) @@ -272,6 +281,11 @@ option_parser.add_option('--device-flags', dest='device_flags', default='', help='The relative filepath to a file containing ' 'command-line flags to set on the device') + option_parser.add_option('--isolate_file_path', + '--isolate-file-path', + dest='isolate_file_path', + help='.isolate file path to override the default ' + 'path') def ProcessInstrumentationOptions(options, error_func): @@ -334,7 +348,8 @@ options.test_apk_jar_path, options.test_runner, options.test_support_apk_path, - options.device_flags + options.device_flags, + options.isolate_file_path ) @@ -657,7 +672,8 @@ exit_code = 0 if options.run_java_tests: - runner_factory, tests = instrumentation_setup.Setup(instrumentation_options) + runner_factory, tests = instrumentation_setup.Setup( + instrumentation_options, devices) test_results, exit_code = test_dispatcher.RunTests( tests, runner_factory, devices, shard=True, test_timeout=None,
diff --git a/build/android/tests/multiple_proguards/src/dummy/DummyActivity.java b/build/android/tests/multiple_proguards/src/dummy/DummyActivity.java index 72f20f4..e138acc 100644 --- a/build/android/tests/multiple_proguards/src/dummy/DummyActivity.java +++ b/build/android/tests/multiple_proguards/src/dummy/DummyActivity.java
@@ -22,5 +22,5 @@ private static void doBadThings2() { sun.reflect.Reflection.getCallerClass(2); - } + } }
diff --git a/build/common.gypi b/build/common.gypi index 0d7d385..77939be 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -41,7 +41,7 @@ 'conditions': [ # Compute the architecture that we're building on. - ['OS=="win" or OS=="mac" or OS=="ios"', { + ['OS=="win" or OS=="ios"', { 'host_arch%': 'ia32', }, { 'host_arch%': '<!pymod_do_main(detect_host_arch)', @@ -997,8 +997,8 @@ # TODO(baixo): Enable v8_use_external_startup_data # http://crbug.com/421063 - ['android_webview_build==0 and android_webview_telemetry_build==0 and chromecast==0', { - 'v8_use_external_startup_data': 0, + ['android_webview_build==0 and android_webview_telemetry_build==0 and chromecast==0 and OS=="android"', { + 'v8_use_external_startup_data': 1, }, { 'v8_use_external_startup_data': 0, }], @@ -2275,6 +2275,11 @@ 'arm_thumb%': 1, }], + # Set default compiler flags depending on MIPS architecture variant. + ['target_arch=="mipsel" and mips_arch_variant=="r2" and android_webview_build==0', { + 'mips_fpu_mode%': 'fp32', + }], + ['android_webview_build==1', { # The WebView build gets its cpu-specific flags from the Android build system. 'arm_arch%': '', @@ -2282,6 +2287,7 @@ 'arm_fpu%': '', 'arm_float_abi%': '', 'arm_thumb%': 0, + 'mips_fpu_mode%': '', }], # Enable brlapi by default for chromeos. @@ -3164,6 +3170,12 @@ 'credui.lib', 'netapi32.lib', ], + 'AdditionalOptions': [ + # Suggested by Microsoft Devrel to avoid + # LINK : fatal error LNK1248: image size (80000000) exceeds maximum allowable size (80000000) + # which started happening more regularly after VS2013 Update 4. + '/maxilksize:2147483647', + ], }, }, }, @@ -5405,7 +5417,6 @@ # removed as code is fixed. 4100, # Unreferenced formal parameter 4121, # Alignment of a member was sensitive to packing - 4189, # Local variable is initialized but not referenced 4244, # Conversion from 'type1' to 'type2', possible loss of data 4481, # Nonstandard extension used: override specifier 'keyword' 4505, # Unreferenced local function has been removed
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 7120bac..0568527 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -213,6 +213,10 @@ if (requires_android) { args += [ "--requires-android" ] } + if (defined(invoker.bypass_platform_checks) && + invoker.bypass_platform_checks) { + args += [ "--bypass-platform-checks" ] + } if (is_android_resources || is_apk) { assert(defined(invoker.resources_zip)) @@ -634,12 +638,6 @@ args += [ "--chromium-code=1" ] } - if (defined(invoker.main_class)) { - args += [ - "--main-class", invoker.main_class - ] - } - args += rebase_path(_java_files, root_build_dir) } @@ -699,6 +697,8 @@ type = "java_library" supports_android = _supports_android requires_android = _requires_android + bypass_platform_checks = (defined(invoker.bypass_platform_checks) && + invoker.bypass_platform_checks) deps = [] if (defined(invoker.deps)) { @@ -764,7 +764,6 @@ android = _requires_android if (defined(invoker.jar_excluded_patterns)) { jar_excluded_patterns = invoker.jar_excluded_patterns } - if (defined(invoker.main_class)) { main_class = invoker.main_class } if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess } if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config } if (defined(invoker.dist_jar_path)) { dist_jar_path = invoker.dist_jar_path }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 3f54c43..938a090 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -655,6 +655,10 @@ # srcjars: List of srcjars to be included in this library, together with the # ones obtained from srcjar_deps. # +# bypass_platform_checks: Disables checks about cross-platform (Java/Android) +# dependencies for this target. This will allow depending on an +# android_library target, for example. +# # chromium_code: If true, extra analysis warning/errors will be enabled. # # datadeps, testonly @@ -676,6 +680,7 @@ if (defined(invoker.java_files)) { java_files = invoker.java_files } if (defined(invoker.srcjar_deps)) { srcjar_deps = invoker.srcjar_deps } if (defined(invoker.srcjars)) { srcjars = invoker.srcjars } + if (defined(invoker.bypass_platform_checks)) { bypass_platform_checks = invoker.bypass_platform_checks } if (defined(invoker.testonly)) { testonly = invoker.testonly } main_class = invoker.main_class @@ -709,10 +714,9 @@ # supports_android: If true, Android targets (android_library, android_apk) # may depend on this target. Note: if true, this target must only use the # subset of Java available on Android. -# requires_android_platform: If true, this library may depend on -# android-specific targets. If this is the case, there should be some -# android-platform-like implementation available at runtime (Android, -# robolectric, etc). +# bypass_platform_checks: Disables checks about cross-platform (Java/Android) +# dependencies for this target. This will allow depending on an +# android_library target, for example. # # datadeps, testonly # @@ -745,17 +749,13 @@ if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess } if (defined(invoker.srcjar_deps)) { srcjar_deps = invoker.srcjar_deps } if (defined(invoker.srcjars)) { srcjars = invoker.srcjars } + if (defined(invoker.bypass_platform_checks)) { bypass_platform_checks = invoker.bypass_platform_checks } if (defined(invoker.testonly)) { testonly = invoker.testonly } if (defined(invoker.jar_path)) { jar_path = invoker.jar_path } if (defined(invoker.supports_android) && invoker.supports_android) { supports_android = true } - if (defined(invoker.requires_android_platform) - && invoker.requires_android_platform) { - supports_android = true - requires_android = true - } } }
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 0d9e501..ae12eda 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -691,7 +691,6 @@ "/wd4100", # Unreferenced formal function parameter. "/wd4121", # Alignment of a member was sensitive to packing. - "/wd4189", # A variable was declared and initialized but never used. "/wd4244", # Conversion: possible loss of data. "/wd4481", # Nonstandard extension: override specifier. "/wd4505", # Unreferenced local function has been removed.
diff --git a/build/config/features.gni b/build/config/features.gni index 82247b9..9953a0d 100644 --- a/build/config/features.gni +++ b/build/config/features.gni
@@ -94,9 +94,7 @@ # disables it, 1 enables it fully, and 2 enables only UI and reporting features # without enabling phishing and malware detection. This is useful to integrate # a third party phishing/malware detection to existing safe browsing logic. -if (is_android) { - safe_browsing_mode = 2 -} else if (is_ios) { +if (is_ios) { safe_browsing_mode = 0 } else { safe_browsing_mode = 1
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn index 58e310f..f623064 100644 --- a/build/config/win/BUILD.gn +++ b/build/config/win/BUILD.gn
@@ -16,19 +16,10 @@ "NTDDI_VERSION=0x06030000", "PSAPI_VERSION=1", "WIN32", + "_SECURE_ATL", ] include_dirs = system_include_dirs - - if (is_visual_studio_express) { - # https://code.google.com/p/chromium/issues/detail?id=372451#c20 - # Warning 4702 ("Unreachable code") should be re-enabled once Express users - # are updated to VS2013 Update 2. - cflags = [ "/wd4702" ] - } else { - # Only supported on non-Express versions. - defines += [ "_SECURE_ATL" ] - } } # Sets the default Windows build version. This is separated because some @@ -49,9 +40,6 @@ "$visual_studio_path\VC\lib\amd64", "$visual_studio_path\VC\atlmfc\lib\amd64", ] - if (is_visual_studio_express) { - lib_dirs += [ "$wdk_path/lib/ATL/amd64" ] - } } else { ldflags = [ "/MACHINE:X86", @@ -62,26 +50,10 @@ "$visual_studio_path\VC\lib", "$visual_studio_path\VC\atlmfc\lib", ] - if (is_visual_studio_express) { - lib_dirs += [ "$wdk_path/lib/ATL/i386" ] - } if (!is_asan) { ldflags += [ "/largeaddressaware" ] } } - - if (is_visual_studio_express) { - # Explicitly required when using the ATL with express. - libs = [ "atlthunk.lib" ] - - # ATL 8.0 included in WDK 7.1 makes the linker to generate almost eight - # hundred LNK4254 and LNK4078 warnings: - # - warning LNK4254: section 'ATL' (50000040) merged into '.rdata' - # (40000040) with different attributes - # - warning LNK4078: multiple 'ATL' sections found with different - # attributes - ldflags += [ "/ignore:4254", "/ignore:4078" ] - } } # This default linker setup is provided separately from the SDK setup so
diff --git a/build/config/win/visual_studio_version.gni b/build/config/win/visual_studio_version.gni index c0b18c7..24c00cd 100644 --- a/build/config/win/visual_studio_version.gni +++ b/build/config/win/visual_studio_version.gni
@@ -19,7 +19,7 @@ # Full path to the Windows SDK, not including a backslash at the end. # This value is the default location, override if you have a different # installation location. - windows_sdk_path = "C:\Program Files (x86)\Windows Kits\8.0" + windows_sdk_path = "C:\Program Files (x86)\Windows Kits\8.1" # The list of include directories that are treated as "system" include # directories. TODO(scottmg): These are incorrectly put on the command line @@ -34,17 +34,15 @@ windows_sdk_path = toolchain_data.sdk_path visual_studio_version = toolchain_data.vs_version wdk_path = toolchain_data.wdk_dir + visual_studio_runtime_dirs = toolchain_data.runtime_dirs } else { assert(visual_studio_version != "", "You must set the visual_studio_version if you set the path") assert(wdk_path != "", "You must set the wdk_path if you set the visual studio path") + visual_studio_runtime_dirs = [] } -# Set when using the "Express" version of a Visual Studio version we support. -is_visual_studio_express = (visual_studio_version == "2013e") - - # The Windows SDK include directories must be first. They both have a sal.h, # and the SDK one is newer and the SDK uses some newer features from it not # present in the Visual Studio one. @@ -55,10 +53,3 @@ "$visual_studio_path\VC\include", "$visual_studio_path\VC\atlmfc\include", ] - -if (is_visual_studio_express) { - system_include_dirs += [ - "$wdk_path/inc/atl71", - "$wdk_path/inc/mfc42", - ] -}
diff --git a/build/download_nacl_toolchains.py b/build/download_nacl_toolchains.py index 3d6c64f..7402689 100755 --- a/build/download_nacl_toolchains.py +++ b/build/download_nacl_toolchains.py
@@ -50,6 +50,7 @@ if 'target_arch=arm' not in os.environ.get('GYP_DEFINES', ''): args.extend(['--exclude', 'nacl_arm_newlib']) + args.extend(['--mode', 'nacl_core_sdk']) args.append('sync') package_version.main(args)
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh index f28409b..3093505 100755 --- a/build/install-build-deps.sh +++ b/build/install-build-deps.sh
@@ -105,10 +105,10 @@ libpulse-dev libsctp-dev libspeechd-dev libsqlite3-dev libssl-dev libudev-dev libwww-perl libxslt1-dev libxss-dev libxt-dev libxtst-dev mesa-common-dev openbox patch perl php5-cgi pkg-config python - python-cherrypy3 python-crypto python-dev python-opencv python-openssl - python-psutil rpm ruby subversion ttf-dejavu-core ttf-indic-fonts - ttf-kochi-gothic ttf-kochi-mincho wdiff xfonts-mathml zip - $chromeos_dev_list" + python-cherrypy3 python-crypto python-dev python-numpy python-opencv + python-openssl python-psutil rpm ruby subversion ttf-dejavu-core + ttf-indic-fonts ttf-kochi-gothic ttf-kochi-mincho wdiff xfonts-mathml + zip $chromeos_dev_list" # 64-bit systems need a minimum set of 32-bit compat packages for the pre-built # NaCl binaries.
diff --git a/build/precompile.h b/build/precompile.h index 20ca73c..32c2f11 100644 --- a/build/precompile.h +++ b/build/precompile.h
@@ -27,7 +27,6 @@ #include <Windows.h> #include <dwmapi.h> #include <shellapi.h> -#include <wincrypt.h> // 4 #include <wtypes.h> // 2 // Defines in atlbase.h cause conflicts; if we could figure out how
diff --git a/build/sanitizers/sanitizers.gyp b/build/sanitizers/sanitizers.gyp index d971d6d..64f7cdf 100644 --- a/build/sanitizers/sanitizers.gyp +++ b/build/sanitizers/sanitizers.gyp
@@ -56,6 +56,27 @@ ], }, }, + { + # Copy llvm-symbolizer to the product dir so that LKGR bots can package it. + 'target_name': 'llvm-symbolizer', + 'type': 'none', + 'variables': { + + # Path is relative to this GYP file. + 'llvm_symbolizer_path': + '../../third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer<(EXECUTABLE_SUFFIX)', + }, + 'conditions': [ + ['clang==1', { + 'copies': [{ + 'destination': '<(PRODUCT_DIR)', + 'files': [ + '<(llvm_symbolizer_path)', + ], + }], + }], + ], + }, ], }
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc index 8ee6083..09cf522 100644 --- a/build/sanitizers/tsan_suppressions.cc +++ b/build/sanitizers/tsan_suppressions.cc
@@ -310,6 +310,10 @@ // https://crbug.com/433993 "deadlock:content::WebRtcAudioDeviceImpl\n" +// http://crbug.com/417193 +// Suppressing both AudioContext.{cpp,h}. +"race:modules/webaudio/AudioContext\n" + // End of suppressions. ; // Please keep this semicolon.
diff --git a/build/secondary/third_party/leveldatabase/BUILD.gn b/build/secondary/third_party/leveldatabase/BUILD.gn index ffe9fa6..3653a98 100644 --- a/build/secondary/third_party/leveldatabase/BUILD.gn +++ b/build/secondary/third_party/leveldatabase/BUILD.gn
@@ -23,8 +23,6 @@ sources = [ "env_chromium.cc", "env_chromium.h", - "env_chromium_stdio.cc", - "env_chromium_stdio.h", "env_idb.h", "port/port_chromium.cc", "port/port_chromium.h",
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn index 988683d..87bd254 100644 --- a/build/toolchain/win/BUILD.gn +++ b/build/toolchain/win/BUILD.gn
@@ -16,7 +16,12 @@ gyp_win_tool_path = rebase_path("//tools/gyp/pylib/gyp/win_tool.py", root_build_dir) exec_script("setup_toolchain.py", - [ visual_studio_path, gyp_win_tool_path, windows_sdk_path ]) + [ + visual_studio_path, + gyp_win_tool_path, + windows_sdk_path, + visual_studio_runtime_dirs + ]) # This value will be inherited in the toolchain below. concurrent_links = exec_script("../get_concurrent_links.py", [], "value")
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py index 5e292ab..42c3af1 100644 --- a/build/toolchain/win/setup_toolchain.py +++ b/build/toolchain/win/setup_toolchain.py
@@ -19,39 +19,59 @@ """ -def ExtractImportantEnvironment(): - """Extracts environment variables required for the toolchain from the - current environment.""" +def _ExtractImportantEnvironment(output_of_set): + """Extracts environment variables required for the toolchain to run from + a textual dump output by the cmd.exe 'set' command.""" envvars_to_save = ( - 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma. - 'include', # Needed by midl compiler. + 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma. + 'include', + 'lib', + 'libpath', 'path', 'pathext', 'systemroot', 'temp', 'tmp', ) - result = {} - for envvar in envvars_to_save: - if envvar in os.environ: - envvar = envvar.lower() - if envvar == 'path': - # Our own rules (for running gyp-win-tool) and other actions in - # Chromium rely on python being in the path. Add the path to this - # python here so that if it's not in the path when ninja is run - # later, python will still be found. - result[envvar.upper()] = os.path.dirname(sys.executable) + \ - os.pathsep + os.environ[envvar] - else: - result[envvar.upper()] = os.environ[envvar] + env = {} + for line in output_of_set.splitlines(): + for envvar in envvars_to_save: + if re.match(envvar + '=', line.lower()): + var, setting = line.split('=', 1) + if envvar == 'path': + # Our own rules (for running gyp-win-tool) and other actions in + # Chromium rely on python being in the path. Add the path to this + # python here so that if it's not in the path when ninja is run + # later, python will still be found. + setting = os.path.dirname(sys.executable) + os.pathsep + setting + env[var.upper()] = setting + break for required in ('SYSTEMROOT', 'TEMP', 'TMP'): - if required not in result: + if required not in env: raise Exception('Environment variable "%s" ' 'required to be set to valid path' % required) - return result + return env -def FormatAsEnvironmentBlock(envvar_dict): +def _SetupScript(target_arch, sdk_dir): + """Returns a command (with arguments) to be used to set up the + environment.""" + # Check if we are running in the SDK command line environment and use + # the setup script from the SDK if so. |target_arch| should be either + # 'x86' or 'x64'. + assert target_arch in ('x86', 'x64') + if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1))) and sdk_dir: + return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')), + '/' + target_arch] + else: + # We only support x64-hosted tools. + # TODO(scottmg|dpranke): Non-depot_tools toolchain: need to get Visual + # Studio install location from registry. + return [os.path.normpath(os.path.join(FIND_VS_IN_REG, 'VC/vcvarsall.bat')), + 'amd64_x86' if target_arch == 'x86' else 'amd64'] + + +def _FormatAsEnvironmentBlock(envvar_dict): """Format as an 'environment block' directly suitable for CreateProcess. Briefly this is a list of key=value\0, terminated by an additional \0. See CreateProcess documentation for more details.""" @@ -63,7 +83,7 @@ return block -def CopyTool(source_path): +def _CopyTool(source_path): """Copies the given tool to the current directory, including a warning not to edit it.""" with open(source_path) as source_file: @@ -76,33 +96,39 @@ '# Generated by setup_toolchain.py do not edit.\n'] + tool_source[1:])) -if len(sys.argv) != 4: - print('Usage setup_toolchain.py ' - '<visual studio path> <win tool path> <win sdk path>') - sys.exit(2) -vs_path = sys.argv[1] -tool_source = sys.argv[2] -win_sdk_path = sys.argv[3] -CopyTool(tool_source) +def main(): + if len(sys.argv) != 5: + print('Usage setup_toolchain.py ' + '<visual studio path> <win tool path> <win sdk path> <runtime dirs>') + sys.exit(2) + vs_path = sys.argv[1] + tool_source = sys.argv[2] + win_sdk_path = sys.argv[3] + runtime_dirs = sys.argv[4] -important_env_vars = ExtractImportantEnvironment() -path = important_env_vars["PATH"].split(";") + _CopyTool(tool_source) -# Add 32-bit compiler path to the beginning and write the block. -path32 = [os.path.join(vs_path, "VC\\BIN")] + \ - [os.path.join(win_sdk_path, "bin\\x86")] + \ - path -important_env_vars["PATH"] = ";".join(path32) -environ = FormatAsEnvironmentBlock(important_env_vars) -with open('environment.x86', 'wb') as env_file: - env_file.write(environ) + archs = ('x86', 'x64') + # TODO(scottmg|goma): Do we need an equivalent of + # ninja_use_custom_environment_files? + for arch in archs: + # Extract environment variables for subprocesses. + args = _SetupScript(arch, win_sdk_path) + args.extend(('&&', 'set')) + popen = subprocess.Popen( + args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + variables, _ = popen.communicate() + env = _ExtractImportantEnvironment(variables) + env['PATH'] = runtime_dirs + ';' + env['PATH'] -# Add 64-bit compiler path to the beginning and write the block. -path64 = [os.path.join(vs_path, "VC\\BIN\\amd64")] + \ - [os.path.join(win_sdk_path, "bin\\x64")] + \ - path -important_env_vars["PATH"] = ";".join(path64) -environ = FormatAsEnvironmentBlock(important_env_vars) -with open('environment.x64', 'wb') as env_file: - env_file.write(environ) + # TODO(scottmg|thakis|dpranke): Is there an equivalent to + # msvs_system_include_dirs that we need to inject into INCLUDE here? + + env_block = _FormatAsEnvironmentBlock(env) + with open('environment.' + arch, 'wb') as f: + f.write(env_block) + + +if __name__ == '__main__': + main()
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py index a490a2c..fb7e142 100644 --- a/build/vs_toolchain.py +++ b/build/vs_toolchain.py
@@ -184,11 +184,11 @@ def GetToolchainDir(): """Gets location information about the current toolchain (must have been previously updated by 'update'). This is used for the GN build.""" - SetEnvironmentAndGetRuntimeDllDirs() + runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs() # If WINDOWSSDKDIR is not set, search the default SDK path and set it. if not 'WINDOWSSDKDIR' in os.environ: - default_sdk_path = 'C:\\Program Files (x86)\\Windows Kits\\8.0' + default_sdk_path = 'C:\\Program Files (x86)\\Windows Kits\\8.1' if os.path.isdir(default_sdk_path): os.environ['WINDOWSSDKDIR'] = default_sdk_path @@ -196,11 +196,13 @@ sdk_path = "%s" vs_version = "%s" wdk_dir = "%s" +runtime_dirs = "%s" ''' % ( os.environ['GYP_MSVS_OVERRIDE_PATH'], os.environ['WINDOWSSDKDIR'], os.environ['GYP_MSVS_VERSION'], - os.environ.get('WDK_DIR', '')) + os.environ.get('WDK_DIR', ''), + ';'.join(runtime_dll_dirs)) def main():
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index ab3aab4..6d5fec4 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -266,6 +266,8 @@ "output/render_surface_filters.h", "output/renderer.cc", "output/renderer.h", + "output/renderer_settings.cc", + "output/renderer_settings.h", "output/shader.cc", "output/shader.h", "output/software_frame_data.cc",
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn index 9fd2f33..fac991b 100644 --- a/cc/blink/BUILD.gn +++ b/cc/blink/BUILD.gn
@@ -65,22 +65,25 @@ } # GYP version: //cc/blink/cc_blink_tests.gyp:cc_blink_unittests -test("cc_blink_unittests") { - deps = [ - ":blink", - "//base/test:run_all_unittests", - "//base/third_party/dynamic_annotations", - "//skia", - "//testing/gtest", - "//ui/gfx/geometry", - "//ui/gfx:test_support", - "//cc", - "//cc:test_support", - ] +# TODO(GYP): make linking work on the mac. +if (!is_mac) { + test("cc_blink_unittests") { + deps = [ + ":blink", + "//base/test:run_all_unittests", + "//base/third_party/dynamic_annotations", + "//skia", + "//testing/gtest", + "//ui/gfx/geometry", + "//ui/gfx:test_support", + "//cc", + "//cc:test_support", + ] - sources = [ - "web_animation_unittest.cc", - "web_float_animation_curve_unittest.cc", - "web_layer_impl_fixed_bounds_unittest.cc", - ] + sources = [ + "web_animation_unittest.cc", + "web_float_animation_curve_unittest.cc", + "web_layer_impl_fixed_bounds_unittest.cc", + ] + } }
diff --git a/cc/cc.gyp b/cc/cc.gyp index fac01a7..046d43c 100644 --- a/cc/cc.gyp +++ b/cc/cc.gyp
@@ -301,6 +301,8 @@ 'output/render_surface_filters.h', 'output/renderer.cc', 'output/renderer.h', + 'output/renderer_settings.cc', + 'output/renderer_settings.h', 'output/shader.cc', 'output/shader.h', 'output/software_frame_data.cc',
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc index 7009c4a..e276a41 100644 --- a/cc/debug/rasterize_and_record_benchmark_impl.cc +++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -196,7 +196,7 @@ void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) { rasterize_results_.total_picture_layers++; - if (!layer->DrawsContent()) { + if (!layer->CanHaveTilings()) { rasterize_results_.total_picture_layers_with_no_content++; return; }
diff --git a/cc/input/page_scale_animation.h b/cc/input/page_scale_animation.h index ce13dcf..0e430c2 100644 --- a/cc/input/page_scale_animation.h +++ b/cc/input/page_scale_animation.h
@@ -10,12 +10,31 @@ #include "base/time/time.h" #include "cc/base/cc_export.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/geometry/vector2d_f.h" namespace cc { class TimingFunction; +// Used in the CC to pass around a scale animation that hasn't yet been +// initialized. +struct PendingPageScaleAnimation { + PendingPageScaleAnimation( + const gfx::Vector2d _target_offset, + bool _use_anchor, + float _scale, + const base::TimeDelta& _duration) + : target_offset(_target_offset), + use_anchor(_use_anchor), + scale(_scale), + duration(_duration) {} + gfx::Vector2d target_offset; + bool use_anchor; + float scale; + base::TimeDelta duration; +}; + // A small helper class that does the math for zoom animations, primarily for // double-tap zoom. Initialize it with starting and ending scroll/page scale // positions and an animation length time, then call ...AtTime() at every frame
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 937aa77..0eb9621 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -125,6 +125,7 @@ twin_layer_ = layer_impl; layer_impl->twin_layer_ = this; + layer_impl->set_is_mask(is_mask_); layer_impl->UpdateRasterSource(raster_source_); DCHECK_IMPLIES(raster_source_->IsSolidColor(), tilings_->num_tilings() == 0); @@ -885,16 +886,6 @@ return tiling; } -void PictureLayerImpl::RemoveTiling(float contents_scale) { - if (!tilings_ || tilings_->num_tilings() == 0) - return; - - tilings_->RemoveTilingWithScale(contents_scale); - if (tilings_->num_tilings() == 0) - ResetRasterScale(); - SanityCheckTilingState(); -} - void PictureLayerImpl::RemoveAllTilings() { if (tilings_) tilings_->RemoveAllTilings(); @@ -1096,7 +1087,6 @@ raster_contents_scale_, ideal_contents_scale_); float max_acceptable_high_res_scale = std::max( raster_contents_scale_, ideal_contents_scale_); - float twin_low_res_scale = 0.f; PictureLayerImpl* twin = GetPendingOrActiveTwinLayer(); if (twin && twin->CanHaveTilings()) { @@ -1106,63 +1096,23 @@ max_acceptable_high_res_scale = std::max( max_acceptable_high_res_scale, std::max(twin->raster_contents_scale_, twin->ideal_contents_scale_)); - - // TODO(danakj): Remove the tilings_ check when we create them in the - // constructor. - if (twin->tilings_) { - PictureLayerTiling* tiling = - twin->tilings_->FindTilingWithResolution(LOW_RESOLUTION); - if (tiling) - twin_low_res_scale = tiling->contents_scale(); - } } - // TODO(vmpstr): Put this logic into PictureLayerTilingSet. - std::vector<PictureLayerTiling*> to_remove; - for (size_t i = 0; i < tilings_->num_tilings(); ++i) { - PictureLayerTiling* tiling = tilings_->tiling_at(i); - - // Keep multiple high resolution tilings even if not used to help - // activate earlier at non-ideal resolutions. - if (tiling->contents_scale() >= min_acceptable_high_res_scale && - tiling->contents_scale() <= max_acceptable_high_res_scale) - continue; - - // Keep low resolution tilings, if the layer should have them. - if (layer_tree_impl()->create_low_res_tiling()) { - if (tiling->resolution() == LOW_RESOLUTION || - tiling->contents_scale() == twin_low_res_scale) - continue; - } - - // Don't remove tilings that are being used (and thus would cause a flash.) - if (std::find(used_tilings.begin(), used_tilings.end(), tiling) != - used_tilings.end()) - continue; - - to_remove.push_back(tiling); - } - - if (to_remove.empty()) - return; - + PictureLayerTilingSet* twin_set = twin ? twin->tilings_.get() : nullptr; PictureLayerImpl* recycled_twin = GetRecycledTwinLayer(); - // Remove tilings on this tree and the twin tree. - for (size_t i = 0; i < to_remove.size(); ++i) { - const PictureLayerTiling* twin_tiling = - GetPendingOrActiveTwinTiling(to_remove[i]); - // Only remove tilings from the twin layer if they have - // NON_IDEAL_RESOLUTION. - if (twin_tiling && twin_tiling->resolution() == NON_IDEAL_RESOLUTION) - twin->RemoveTiling(to_remove[i]->contents_scale()); - // Remove the tiling from the recycle tree. Note that we ignore resolution, - // since we don't need to maintain high/low res on the recycle tree. - if (recycled_twin) - recycled_twin->RemoveTiling(to_remove[i]->contents_scale()); - // TODO(enne): temporary sanity CHECK for http://crbug.com/358350 - CHECK_NE(HIGH_RESOLUTION, to_remove[i]->resolution()); - tilings_->Remove(to_remove[i]); - } + PictureLayerTilingSet* recycled_twin_set = + recycled_twin ? recycled_twin->tilings_.get() : nullptr; + + tilings_->CleanUpTilings(min_acceptable_high_res_scale, + max_acceptable_high_res_scale, used_tilings, + layer_tree_impl()->create_low_res_tiling(), twin_set, + recycled_twin_set); + + if (twin_set && twin_set->num_tilings() == 0) + twin->ResetRasterScale(); + + if (recycled_twin_set && recycled_twin_set->num_tilings() == 0) + recycled_twin->ResetRasterScale(); DCHECK_GT(tilings_->num_tilings(), 0u); SanityCheckTilingState();
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h index 12209a8..9a77546 100644 --- a/cc/layers/picture_layer_impl.h +++ b/cc/layers/picture_layer_impl.h
@@ -144,6 +144,8 @@ void RunMicroBenchmark(MicroBenchmarkImpl* benchmark) override; + bool CanHaveTilings() const; + // Functions used by tile manager. PictureLayerImpl* GetPendingOrActiveTwinLayer() const; bool IsOnActiveOrPendingTree() const; @@ -158,7 +160,6 @@ PictureLayerImpl(LayerTreeImpl* tree_impl, int id); PictureLayerTiling* AddTiling(float contents_scale); - void RemoveTiling(float contents_scale); void RemoveAllTilings(); void SyncFromActiveLayer(const PictureLayerImpl* other); void AddTilingsForRasterScale(); @@ -179,7 +180,6 @@ } void DoPostCommitInitialization(); - bool CanHaveTilings() const; bool CanHaveTilingWithScale(float contents_scale) const; void SanityCheckTilingState() const; // Checks if all tiles required for a certain action (e.g. activation) are
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 931e979..246e625 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -1226,6 +1226,15 @@ EXPECT_NE(0u, mask_resource_id); EXPECT_EQ(mask_texture_size, active_layer_->bounds()); + // Drop resources and recreate them, still the same. + old_pending_layer_->ReleaseResources(); + active_layer_->ReleaseResources(); + SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false); + active_layer_->HighResTiling()->CreateAllTilesForTesting(); + EXPECT_EQ(1u, active_layer_->HighResTiling()->AllTilesForTesting().size()); + EXPECT_NE(0u, mask_resource_id); + EXPECT_EQ(mask_texture_size, active_layer_->bounds()); + // Resize larger than the max texture size. int max_texture_size = host_impl_.GetRendererCapabilities().max_texture_size; scoped_refptr<FakePicturePileImpl> huge_pile = @@ -1249,6 +1258,15 @@ // The mask resource is empty. active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size); EXPECT_EQ(0u, mask_resource_id); + + // Drop resources and recreate them, still the same. + old_pending_layer_->ReleaseResources(); + active_layer_->ReleaseResources(); + SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false); + active_layer_->HighResTiling()->CreateAllTilesForTesting(); + EXPECT_EQ(0u, active_layer_->HighResTiling()->AllTilesForTesting().size()); + active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size); + EXPECT_EQ(0u, mask_resource_id); } TEST_F(PictureLayerImplTest, ScaledMaskLayer) {
diff --git a/cc/layers/ui_resource_layer.cc b/cc/layers/ui_resource_layer.cc index 944cf7d..9d711fe 100644 --- a/cc/layers/ui_resource_layer.cc +++ b/cc/layers/ui_resource_layer.cc
@@ -107,23 +107,26 @@ Layer::SetLayerTreeHost(host); - // Recreate the resource hold against the new LTH. + // Recreate the resource held against the new LTH. RecreateUIResourceHolder(); + + UpdateDrawsContent(HasDrawableContent()); } void UIResourceLayer::RecreateUIResourceHolder() { - ui_resource_holder_ = nullptr; - if (layer_tree_host() && !bitmap_.empty()) { - ui_resource_holder_ = - ScopedUIResourceHolder::Create(layer_tree_host(), bitmap_); - } - UpdateDrawsContent(HasDrawableContent()); + if (!bitmap_.empty()) + SetBitmap(bitmap_); } void UIResourceLayer::SetBitmap(const SkBitmap& skbitmap) { bitmap_ = skbitmap; - - RecreateUIResourceHolder(); + if (layer_tree_host() && !bitmap_.empty()) { + ui_resource_holder_ = + ScopedUIResourceHolder::Create(layer_tree_host(), bitmap_); + } else { + ui_resource_holder_ = nullptr; + } + UpdateDrawsContent(HasDrawableContent()); SetNeedsCommit(); }
diff --git a/cc/layers/ui_resource_layer.h b/cc/layers/ui_resource_layer.h index 3bfd9b2..dc2006e 100644 --- a/cc/layers/ui_resource_layer.h +++ b/cc/layers/ui_resource_layer.h
@@ -26,7 +26,9 @@ void SetBitmap(const SkBitmap& skbitmap); - // An alternative way of setting the resource to allow for sharing. + // An alternative way of setting the resource to allow for sharing. If you use + // this method, you are responsible for updating the ID if the layer moves + // between compositors. void SetUIResourceId(UIResourceId resource_id); // Sets a UV transform to be used at draw time. Defaults to (0, 0) and (1, 1). @@ -62,8 +64,6 @@ scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; void RecreateUIResourceHolder(); - - DISALLOW_COPY_AND_ASSIGN(UIResourceLayer); };
diff --git a/cc/layers/ui_resource_layer_unittest.cc b/cc/layers/ui_resource_layer_unittest.cc index 09d57a9..239efb8 100644 --- a/cc/layers/ui_resource_layer_unittest.cc +++ b/cc/layers/ui_resource_layer_unittest.cc
@@ -28,12 +28,29 @@ namespace cc { namespace { +class TestUIResourceLayer : public UIResourceLayer { + public: + static scoped_refptr<TestUIResourceLayer> Create() { + return make_scoped_refptr(new TestUIResourceLayer()); + } + + UIResourceId GetUIResourceId() { + if (ui_resource_holder_) + return ui_resource_holder_->id(); + return 0; + } + + protected: + TestUIResourceLayer() : UIResourceLayer() { SetIsDrawable(true); } + ~TestUIResourceLayer() override {} +}; + class UIResourceLayerTest : public testing::Test { public: UIResourceLayerTest() : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {} protected: - virtual void SetUp() { + void SetUp() override { layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_); layer_tree_host_->InitializeSingleThreaded( &fake_client_, @@ -41,7 +58,7 @@ nullptr); } - virtual void TearDown() { + void TearDown() override { Mock::VerifyAndClearExpectations(layer_tree_host_.get()); } @@ -50,9 +67,8 @@ }; TEST_F(UIResourceLayerTest, SetBitmap) { - scoped_refptr<UIResourceLayer> test_layer = UIResourceLayer::Create(); + scoped_refptr<UIResourceLayer> test_layer = TestUIResourceLayer::Create(); ASSERT_TRUE(test_layer.get()); - test_layer->SetIsDrawable(true); test_layer->SetBounds(gfx::Size(100, 100)); layer_tree_host_->SetRootLayer(test_layer); @@ -78,9 +94,8 @@ } TEST_F(UIResourceLayerTest, SetUIResourceId) { - scoped_refptr<UIResourceLayer> test_layer = UIResourceLayer::Create(); + scoped_refptr<TestUIResourceLayer> test_layer = TestUIResourceLayer::Create(); ASSERT_TRUE(test_layer.get()); - test_layer->SetIsDrawable(true); test_layer->SetBounds(gfx::Size(100, 100)); layer_tree_host_->SetRootLayer(test_layer); @@ -102,6 +117,15 @@ test_layer->Update(&queue, &occlusion_tracker); EXPECT_TRUE(test_layer->DrawsContent()); + + // ID is preserved even when you set ID first and attach it to the tree. + layer_tree_host_->SetRootLayer(nullptr); + scoped_ptr<ScopedUIResource> shared_resource = ScopedUIResource::Create( + layer_tree_host_.get(), UIResourceBitmap(gfx::Size(5, 5), is_opaque)); + test_layer->SetUIResourceId(shared_resource->id()); + layer_tree_host_->SetRootLayer(test_layer); + EXPECT_EQ(shared_resource->id(), test_layer->GetUIResourceId()); + EXPECT_TRUE(test_layer->DrawsContent()); } } // namespace
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc index fc7098f..0be9318 100644 --- a/cc/output/begin_frame_args.cc +++ b/cc/output/begin_frame_args.cc
@@ -9,6 +9,21 @@ namespace cc { +const char* BeginFrameArgs::TypeToString(BeginFrameArgsType type) { + switch (type) { + case BeginFrameArgs::INVALID: + return "INVALID"; + case BeginFrameArgs::NORMAL: + return "NORMAL"; + case BeginFrameArgs::SYNCHRONOUS: + return "SYNCHRONOUS"; + case BeginFrameArgs::MISSED: + return "MISSED"; + } + NOTREACHED(); + return "???"; +} + BeginFrameArgs::BeginFrameArgs() : frame_time(base::TimeTicks()), deadline(base::TimeTicks()), @@ -26,19 +41,12 @@ type(type) { } -BeginFrameArgs BeginFrameArgs::CreateTyped( - base::TimeTicks frame_time, - base::TimeTicks deadline, - base::TimeDelta interval, - BeginFrameArgs::BeginFrameArgsType type) { - DCHECK_NE(type, BeginFrameArgs::INVALID); - return BeginFrameArgs(frame_time, deadline, interval, type); -} - BeginFrameArgs BeginFrameArgs::Create(base::TimeTicks frame_time, base::TimeTicks deadline, - base::TimeDelta interval) { - return CreateTyped(frame_time, deadline, interval, BeginFrameArgs::NORMAL); + base::TimeDelta interval, + BeginFrameArgs::BeginFrameArgsType type) { + DCHECK_NE(type, BeginFrameArgs::INVALID); + return BeginFrameArgs(frame_time, deadline, interval, type); } scoped_refptr<base::debug::ConvertableToTraceFormat> BeginFrameArgs::AsValue() @@ -51,35 +59,12 @@ void BeginFrameArgs::AsValueInto(base::debug::TracedValue* state) const { state->SetString("type", "BeginFrameArgs"); - switch (type) { - case BeginFrameArgs::INVALID: - state->SetString("subtype", "INVALID"); - break; - case BeginFrameArgs::NORMAL: - state->SetString("subtype", "NORMAL"); - break; - case BeginFrameArgs::SYNCHRONOUS: - state->SetString("subtype", "SYNCHRONOUS"); - break; - case BeginFrameArgs::MISSED: - state->SetString("subtype", "MISSED"); - break; - } + state->SetString("subtype", TypeToString(type)); state->SetDouble("frame_time_us", frame_time.ToInternalValue()); state->SetDouble("deadline_us", deadline.ToInternalValue()); state->SetDouble("interval_us", interval.InMicroseconds()); } -BeginFrameArgs BeginFrameArgs::CreateForSynchronousCompositor( - base::TimeTicks now) { - // For WebView/SynchronousCompositor, we always want to draw immediately, - // so we set the deadline to 0 and guess that the interval is 16 milliseconds. - if (now.is_null()) - now = gfx::FrameTime::Now(); - return CreateTyped( - now, base::TimeTicks(), DefaultInterval(), BeginFrameArgs::SYNCHRONOUS); -} - // This is a hard-coded deadline adjustment that assumes 60Hz, to be used in // cases where a good estimated draw time is not known. Using 1/3 of the vsync // as the default adjustment gives the Browser the last 1/3 of a frame to
diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h index c35a500..0be5241 100644 --- a/cc/output/begin_frame_args.h +++ b/cc/output/begin_frame_args.h
@@ -26,6 +26,7 @@ SYNCHRONOUS, MISSED, }; + static const char* TypeToString(BeginFrameArgsType type); // Creates an invalid set of values. BeginFrameArgs(); @@ -34,13 +35,8 @@ // created by searching for "BeginFrameArgs::Create". static BeginFrameArgs Create(base::TimeTicks frame_time, base::TimeTicks deadline, - base::TimeDelta interval); - static BeginFrameArgs CreateTyped(base::TimeTicks frame_time, - base::TimeTicks deadline, - base::TimeDelta interval, - BeginFrameArgsType type); - static BeginFrameArgs CreateForSynchronousCompositor( - base::TimeTicks now = base::TimeTicks()); + base::TimeDelta interval, + BeginFrameArgsType type); // This is the default delta that will be used to adjust the deadline when // proper draw-time estimations are not yet available.
diff --git a/cc/output/begin_frame_args_unittest.cc b/cc/output/begin_frame_args_unittest.cc index e0c8b3e..9d77a45 100644 --- a/cc/output/begin_frame_args_unittest.cc +++ b/cc/output/begin_frame_args_unittest.cc
@@ -26,15 +26,29 @@ EXPECT_EQ(1, args2.frame_time.ToInternalValue()); EXPECT_EQ(2, args2.deadline.ToInternalValue()); EXPECT_EQ(3, args2.interval.ToInternalValue()); + EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type); BeginFrameArgs args3 = CreateExpiredBeginFrameArgsForTesting(); EXPECT_TRUE(args3.IsValid()) << args3; EXPECT_GT(gfx::FrameTime::Now(), args3.deadline); + EXPECT_EQ(BeginFrameArgs::NORMAL, args3.type); + + BeginFrameArgs args4 = + CreateBeginFrameArgsForTesting(1, 2, 3, BeginFrameArgs::MISSED); + EXPECT_TRUE(args4.IsValid()) << args4; + EXPECT_EQ(1, args4.frame_time.ToInternalValue()); + EXPECT_EQ(2, args4.deadline.ToInternalValue()); + EXPECT_EQ(3, args4.interval.ToInternalValue()); + EXPECT_EQ(BeginFrameArgs::MISSED, args4.type); // operator== EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6), CreateBeginFrameArgsForTesting(4, 5, 6)); + EXPECT_NONFATAL_FAILURE( + EXPECT_EQ(CreateBeginFrameArgsForTesting(7, 8, 9, BeginFrameArgs::MISSED), + CreateBeginFrameArgsForTesting(7, 8, 9)), + ""); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6), CreateBeginFrameArgsForTesting(7, 8, 9)), ""); @@ -42,15 +56,15 @@ // operator<< std::stringstream out1; out1 << args1; - EXPECT_EQ("BeginFrameArgs(0, 0, -1us)", out1.str()); + EXPECT_EQ("BeginFrameArgs(NORMAL, 0, 0, -1us)", out1.str()); std::stringstream out2; out2 << args2; - EXPECT_EQ("BeginFrameArgs(1, 2, 3us)", out2.str()); + EXPECT_EQ("BeginFrameArgs(NORMAL, 1, 2, 3us)", out2.str()); // PrintTo - EXPECT_EQ(std::string("BeginFrameArgs(0, 0, -1us)"), + EXPECT_EQ(std::string("BeginFrameArgs(NORMAL, 0, 0, -1us)"), ::testing::PrintToString(args1)); - EXPECT_EQ(std::string("BeginFrameArgs(1, 2, 3us)"), + EXPECT_EQ(std::string("BeginFrameArgs(NORMAL, 1, 2, 3us)"), ::testing::PrintToString(args2)); } @@ -59,18 +73,15 @@ BeginFrameArgs args1; EXPECT_FALSE(args1.IsValid()) << args1; - BeginFrameArgs args2 = - BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(1), - base::TimeTicks::FromInternalValue(2), - base::TimeDelta::FromInternalValue(3)); + BeginFrameArgs args2 = BeginFrameArgs::Create( + base::TimeTicks::FromInternalValue(1), + base::TimeTicks::FromInternalValue(2), + base::TimeDelta::FromInternalValue(3), BeginFrameArgs::NORMAL); EXPECT_TRUE(args2.IsValid()) << args2; EXPECT_EQ(1, args2.frame_time.ToInternalValue()) << args2; EXPECT_EQ(2, args2.deadline.ToInternalValue()) << args2; EXPECT_EQ(3, args2.interval.ToInternalValue()) << args2; - - base::TimeTicks now = base::TimeTicks::FromInternalValue(1); - EXPECT_EQ(CreateBeginFrameArgsForTesting(1, 0, 16666), - BeginFrameArgs::CreateForSynchronousCompositor(now)); + EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type) << args2; } } // namespace
diff --git a/cc/output/delegating_renderer.cc b/cc/output/delegating_renderer.cc index dc951af..c05c32f 100644 --- a/cc/output/delegating_renderer.cc +++ b/cc/output/delegating_renderer.cc
@@ -22,7 +22,7 @@ scoped_ptr<DelegatingRenderer> DelegatingRenderer::Create( RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) { return make_scoped_ptr(new DelegatingRenderer( @@ -30,7 +30,7 @@ } DelegatingRenderer::DelegatingRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) : Renderer(client, settings),
diff --git a/cc/output/delegating_renderer.h b/cc/output/delegating_renderer.h index 89b47ad..b2bc01f 100644 --- a/cc/output/delegating_renderer.h +++ b/cc/output/delegating_renderer.h
@@ -19,7 +19,7 @@ public: static scoped_ptr<DelegatingRenderer> Create( RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider); ~DelegatingRenderer() override; @@ -39,7 +39,7 @@ private: DelegatingRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider);
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc index 50d82d0..93d7fb1 100644 --- a/cc/output/direct_renderer.cc +++ b/cc/output/direct_renderer.cc
@@ -125,7 +125,7 @@ } DirectRenderer::DirectRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) : Renderer(client, settings),
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h index 40fff83..e07cb93 100644 --- a/cc/output/direct_renderer.h +++ b/cc/output/direct_renderer.h
@@ -59,7 +59,7 @@ protected: DirectRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider);
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index cb6189e..49af1c3 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -289,7 +289,7 @@ scoped_ptr<GLRenderer> GLRenderer::Create( RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider, TextureMailboxDeleter* texture_mailbox_deleter, @@ -303,7 +303,7 @@ } GLRenderer::GLRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider, TextureMailboxDeleter* texture_mailbox_deleter,
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h index ecadebb..22e7706 100644 --- a/cc/output/gl_renderer.h +++ b/cc/output/gl_renderer.h
@@ -49,7 +49,7 @@ static scoped_ptr<GLRenderer> Create( RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider, TextureMailboxDeleter* texture_mailbox_deleter, @@ -74,7 +74,7 @@ protected: GLRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider, TextureMailboxDeleter* texture_mailbox_deleter,
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc index 2af953e..2ac339d 100644 --- a/cc/output/gl_renderer_unittest.cc +++ b/cc/output/gl_renderer_unittest.cc
@@ -172,7 +172,7 @@ class FakeRendererGL : public GLRenderer { public: FakeRendererGL(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) : GLRenderer(client, @@ -215,7 +215,7 @@ void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); } - LayerTreeSettings settings_; + RendererSettings settings_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<FakeOutputSurface> output_surface_; FakeRendererClient renderer_client_; @@ -336,7 +336,7 @@ renderer_->program_shadow_); } - LayerTreeSettings settings_; + RendererSettings settings_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<FakeOutputSurface> output_surface_; FakeRendererClient renderer_client_; @@ -543,7 +543,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -583,7 +583,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -622,7 +622,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -674,7 +674,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -719,7 +719,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -804,7 +804,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -875,7 +875,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -966,7 +966,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; settings.should_clear_root_render_pass = false; FakeRendererClient renderer_client; @@ -1064,7 +1064,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -1162,7 +1162,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; settings.partial_swap_enabled = true; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, @@ -1351,7 +1351,7 @@ false, 1)); - LayerTreeSettings settings; + RendererSettings settings; FakeRendererClient renderer_client; FakeRendererGL renderer(&renderer_client, &settings, @@ -1814,7 +1814,7 @@ ->TestContext3d()); } - LayerTreeSettings settings_; + RendererSettings settings_; FakeOutputSurfaceClient output_surface_client_; StrictMock<MockOutputSurface> output_surface_; scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc index a3a297b..33c6f4a 100644 --- a/cc/output/overlay_unittest.cc +++ b/cc/output/overlay_unittest.cc
@@ -524,7 +524,7 @@ class OverlayInfoRendererGL : public GLRenderer { public: OverlayInfoRendererGL(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) : GLRenderer(client, @@ -601,7 +601,7 @@ void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); } - LayerTreeSettings settings_; + RendererSettings settings_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<OverlayOutputSurface> output_surface_; FakeRendererClient renderer_client_;
diff --git a/cc/output/renderer.h b/cc/output/renderer.h index 1953310..c92ce6f 100644 --- a/cc/output/renderer.h +++ b/cc/output/renderer.h
@@ -80,13 +80,13 @@ void SetVisible(bool visible); protected: - explicit Renderer(RendererClient* client, const LayerTreeSettings* settings) + Renderer(RendererClient* client, const RendererSettings* settings) : client_(client), settings_(settings), visible_(true) {} virtual void DidChangeVisibility() = 0; RendererClient* client_; - const LayerTreeSettings* settings_; + const RendererSettings* settings_; bool visible_; private:
diff --git a/cc/output/renderer_settings.cc b/cc/output/renderer_settings.cc new file mode 100644 index 0000000..bacde5b --- /dev/null +++ b/cc/output/renderer_settings.cc
@@ -0,0 +1,28 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/output/renderer_settings.h" + +#include <limits> + +#include "base/logging.h" + +namespace cc { + +RendererSettings::RendererSettings() + : allow_antialiasing(true), + force_antialiasing(false), + force_blending_with_shaders(false), + partial_swap_enabled(false), + should_clear_root_render_pass(true), + refresh_rate(60.0), + highp_threshold_min(0), + use_rgba_4444_textures(false), + texture_id_allocation_chunk_size(64) { +} + +RendererSettings::~RendererSettings() { +} + +} // namespace cc
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h new file mode 100644 index 0000000..748d230 --- /dev/null +++ b/cc/output/renderer_settings.h
@@ -0,0 +1,31 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_OUTPUT_RENDERER_SETTINGS_H_ +#define CC_OUTPUT_RENDERER_SETTINGS_H_ + +#include "base/basictypes.h" +#include "cc/base/cc_export.h" + +namespace cc { + +class CC_EXPORT RendererSettings { + public: + RendererSettings(); + ~RendererSettings(); + + bool allow_antialiasing; + bool force_antialiasing; + bool force_blending_with_shaders; + bool partial_swap_enabled; + bool should_clear_root_render_pass; + double refresh_rate; + int highp_threshold_min; + bool use_rgba_4444_textures; + size_t texture_id_allocation_chunk_size; +}; + +} // namespace cc + +#endif // CC_OUTPUT_RENDERER_SETTINGS_H_
diff --git a/cc/output/renderer_unittest.cc b/cc/output/renderer_unittest.cc index 6e43cc0..a8f09ff 100644 --- a/cc/output/renderer_unittest.cc +++ b/cc/output/renderer_unittest.cc
@@ -50,14 +50,14 @@ template <class T> scoped_ptr<Renderer> CreateRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider); template <> scoped_ptr<Renderer> CreateRenderer<DelegatingRenderer>( RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) { return DelegatingRenderer::Create( @@ -67,7 +67,7 @@ template <> scoped_ptr<Renderer> CreateRenderer<GLRenderer>( RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) { return GLRenderer::Create( @@ -91,7 +91,7 @@ } FakeRendererClient renderer_client_; - LayerTreeSettings tree_settings_; + RendererSettings tree_settings_; FakeOutputSurfaceClient output_surface_client_; scoped_refptr<MockContextProvider> context_provider_; scoped_ptr<OutputSurface> output_surface_;
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index 442cd8d..ddd3473 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc
@@ -63,7 +63,7 @@ scoped_ptr<SoftwareRenderer> SoftwareRenderer::Create( RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) { return make_scoped_ptr(new SoftwareRenderer( @@ -71,7 +71,7 @@ } SoftwareRenderer::SoftwareRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) : DirectRenderer(client, settings, output_surface, resource_provider), @@ -108,6 +108,7 @@ void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) { TRACE_EVENT0("cc", "SoftwareRenderer::FinishDrawingFrame"); current_framebuffer_lock_ = nullptr; + current_framebuffer_canvas_.clear(); current_canvas_ = NULL; root_canvas_ = NULL; @@ -151,6 +152,7 @@ void SoftwareRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) { DCHECK(!output_surface_->HasExternalStencilTest()); current_framebuffer_lock_ = nullptr; + current_framebuffer_canvas_.clear(); current_canvas_ = root_canvas_; } @@ -161,7 +163,9 @@ current_framebuffer_lock_ = make_scoped_ptr( new ResourceProvider::ScopedWriteLockSoftware( resource_provider_, texture->id())); - current_canvas_ = current_framebuffer_lock_->sk_canvas(); + current_framebuffer_canvas_ = + skia::AdoptRef(new SkCanvas(current_framebuffer_lock_->sk_bitmap())); + current_canvas_ = current_framebuffer_canvas_.get(); InitializeViewport(frame, target_rect, gfx::Rect(target_rect.size()),
diff --git a/cc/output/software_renderer.h b/cc/output/software_renderer.h index 2a672d5..99868c3 100644 --- a/cc/output/software_renderer.h +++ b/cc/output/software_renderer.h
@@ -29,7 +29,7 @@ public: static scoped_ptr<SoftwareRenderer> Create( RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider); @@ -63,7 +63,7 @@ scoped_ptr<CopyOutputRequest> request) override; SoftwareRenderer(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider); @@ -102,6 +102,7 @@ SkPaint current_paint_; scoped_ptr<ResourceProvider::ScopedWriteLockSoftware> current_framebuffer_lock_; + skia::RefPtr<SkCanvas> current_framebuffer_canvas_; scoped_ptr<SoftwareFrameData> current_frame_data_; DISALLOW_COPY_AND_ASSIGN(SoftwareRenderer);
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc index 60f75d9..ea584ee 100644 --- a/cc/output/software_renderer_unittest.cc +++ b/cc/output/software_renderer_unittest.cc
@@ -86,7 +86,7 @@ } protected: - LayerTreeSettings settings_; + RendererSettings settings_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<FakeOutputSurface> output_surface_; scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
diff --git a/cc/resources/bitmap_raster_worker_pool.cc b/cc/resources/bitmap_raster_worker_pool.cc index 3b3739a..a7adf4e 100644 --- a/cc/resources/bitmap_raster_worker_pool.cc +++ b/cc/resources/bitmap_raster_worker_pool.cc
@@ -21,17 +21,20 @@ public: RasterBufferImpl(ResourceProvider* resource_provider, const Resource* resource) - : lock_(resource_provider, resource->id()) {} + : lock_(resource_provider, resource->id()), resource_(resource) {} // Overridden from RasterBuffer: void Playback(const RasterSource* raster_source, const gfx::Rect& rect, float scale) override { - raster_source->PlaybackToCanvas(lock_.sk_canvas(), rect, scale); + RasterWorkerPool::PlaybackToMemory(lock_.sk_bitmap().getPixels(), + resource_->format(), resource_->size(), + 0, raster_source, rect, scale); } private: ResourceProvider::ScopedWriteLockSoftware lock_; + const Resource* resource_; DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); };
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc index 35170a0..51896a5 100644 --- a/cc/resources/picture_layer_tiling_set.cc +++ b/cc/resources/picture_layer_tiling_set.cc
@@ -6,6 +6,7 @@ #include <limits> #include <set> +#include <vector> namespace cc { @@ -50,6 +51,68 @@ tilings_[i]->RemoveTilesInRegion(region); } +void PictureLayerTilingSet::CleanUpTilings( + float min_acceptable_high_res_scale, + float max_acceptable_high_res_scale, + const std::vector<PictureLayerTiling*>& needed_tilings, + bool should_have_low_res, + PictureLayerTilingSet* twin_set, + PictureLayerTilingSet* recycled_twin_set) { + float twin_low_res_scale = 0.f; + if (twin_set) { + PictureLayerTiling* tiling = + twin_set->FindTilingWithResolution(LOW_RESOLUTION); + if (tiling) + twin_low_res_scale = tiling->contents_scale(); + } + + std::vector<PictureLayerTiling*> to_remove; + for (auto* tiling : tilings_) { + // Keep all tilings within the min/max scales. + if (tiling->contents_scale() >= min_acceptable_high_res_scale && + tiling->contents_scale() <= max_acceptable_high_res_scale) { + continue; + } + + // Keep low resolution tilings, if the tiling set should have them. + if (should_have_low_res && + (tiling->resolution() == LOW_RESOLUTION || + tiling->contents_scale() == twin_low_res_scale)) { + continue; + } + + // Don't remove tilings that are required. + if (std::find(needed_tilings.begin(), needed_tilings.end(), tiling) != + needed_tilings.end()) { + continue; + } + + to_remove.push_back(tiling); + } + + for (auto* tiling : to_remove) { + PictureLayerTiling* twin_tiling = + twin_set ? twin_set->FindTilingWithScale(tiling->contents_scale()) + : nullptr; + // Only remove tilings from the twin layer if they have + // NON_IDEAL_RESOLUTION. + if (twin_tiling && twin_tiling->resolution() == NON_IDEAL_RESOLUTION) + twin_set->Remove(twin_tiling); + + PictureLayerTiling* recycled_twin_tiling = + recycled_twin_set + ? recycled_twin_set->FindTilingWithScale(tiling->contents_scale()) + : nullptr; + // Remove the tiling from the recycle tree. Note that we ignore resolution, + // since we don't need to maintain high/low res on the recycle set. + if (recycled_twin_tiling) + recycled_twin_set->Remove(recycled_twin_tiling); + + DCHECK_NE(HIGH_RESOLUTION, tiling->resolution()); + Remove(tiling); + } +} + void PictureLayerTilingSet::MarkAllTilingsNonIdeal() { for (auto* tiling : tilings_) tiling->set_resolution(NON_IDEAL_RESOLUTION); @@ -171,16 +234,6 @@ tilings_.erase(iter); } -void PictureLayerTilingSet::RemoveTilingWithScale(float scale) { - auto iter = std::find_if(tilings_.begin(), tilings_.end(), - [scale](const PictureLayerTiling* tiling) { - return tiling->contents_scale() == scale; - }); - if (iter == tilings_.end()) - return; - tilings_.erase(iter); -} - void PictureLayerTilingSet::RemoveAllTiles() { for (size_t i = 0; i < tilings_.size(); ++i) tilings_[i]->Reset();
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h index 661dd24..f0d0fd7 100644 --- a/cc/resources/picture_layer_tiling_set.h +++ b/cc/resources/picture_layer_tiling_set.h
@@ -6,6 +6,7 @@ #define CC_RESOURCES_PICTURE_LAYER_TILING_SET_H_ #include <set> +#include <vector> #include "cc/base/region.h" #include "cc/base/scoped_ptr_vector.h" @@ -45,6 +46,12 @@ const PictureLayerTilingClient* client() const { return client_; } void RemoveTilesInRegion(const Region& region); + void CleanUpTilings(float min_acceptable_high_res_scale, + float max_acceptable_high_res_scale, + const std::vector<PictureLayerTiling*>& needed_tilings, + bool should_have_low_res, + PictureLayerTilingSet* twin_set, + PictureLayerTilingSet* recycled_twin_set); // Make this set of tilings match the same set of content scales from |other|. // Delete any tilings that don't meet |minimum_contents_scale|. Recreate @@ -85,10 +92,6 @@ // Remove all tilings. void RemoveAllTilings(); - // Remove one tiling. - void Remove(PictureLayerTiling* tiling); - void RemoveTilingWithScale(float scale); - // Remove all tiles; keep all tilings. void RemoveAllTiles(); @@ -154,6 +157,9 @@ private: explicit PictureLayerTilingSet(PictureLayerTilingClient* client); + // Remove one tiling. + void Remove(PictureLayerTiling* tiling); + PictureLayerTilingClient* client_; ScopedPtrVector<PictureLayerTiling> tilings_;
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc index 97cd127..d94ce7c 100644 --- a/cc/resources/picture_pile.cc +++ b/cc/resources/picture_pile.cc
@@ -106,18 +106,17 @@ static_cast<float>(total_record_area); } -float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, - std::vector<gfx::Rect>* record_rects) { +void ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, + std::vector<gfx::Rect>* record_rects) { TRACE_EVENT1("cc", "ClusterTiles", "count", invalid_tiles.size()); - if (invalid_tiles.size() <= 1) { // Quickly handle the special case for common // single-invalidation update, and also the less common // case of no tiles passed in. *record_rects = invalid_tiles; - return 1; + return; } // Sort the invalid tiles by y coordinate. @@ -126,15 +125,14 @@ invalid_tiles_vertical.end(), rect_sort_y); - float vertical_density; std::vector<gfx::Rect> vertical_clustering; - vertical_density = PerformClustering(invalid_tiles_vertical, - &vertical_clustering); + float vertical_density = + PerformClustering(invalid_tiles_vertical, &vertical_clustering); // If vertical density is optimal, then we can return early. if (vertical_density == 1.f) { *record_rects = vertical_clustering; - return vertical_density; + return; } // Now try again with a horizontal sort, see which one is best @@ -143,18 +141,16 @@ invalid_tiles_horizontal.end(), rect_sort_x); - float horizontal_density; std::vector<gfx::Rect> horizontal_clustering; - horizontal_density = PerformClustering(invalid_tiles_horizontal, - &horizontal_clustering); + float horizontal_density = + PerformClustering(invalid_tiles_horizontal, &horizontal_clustering); if (vertical_density < horizontal_density) { *record_rects = horizontal_clustering; - return horizontal_density; + return; } *record_rects = vertical_clustering; - return vertical_density; } } // namespace @@ -190,6 +186,37 @@ bool can_use_lcd_text_changed = can_use_lcd_text_ != can_use_lcd_text; can_use_lcd_text_ = can_use_lcd_text; + gfx::Rect interest_rect = visible_layer_rect; + interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_); + recorded_viewport_ = interest_rect; + recorded_viewport_.Intersect(gfx::Rect(layer_size)); + + bool updated = + ApplyInvalidationAndResize(interest_rect, invalidation, layer_size, + frame_number, can_use_lcd_text_changed); + std::vector<gfx::Rect> invalid_tiles; + GetInvalidTileRects(interest_rect, invalidation, visible_layer_rect, + frame_number, &invalid_tiles); + std::vector<gfx::Rect> record_rects; + ClusterTiles(invalid_tiles, &record_rects); + + if (record_rects.empty()) + return updated; + + CreatePictures(painter, recording_mode, record_rects); + + DetermineIfSolidColor(); + + has_any_recordings_ = true; + DCHECK(CanRasterSlowTileCheck(recorded_viewport_)); + return true; +} + +bool PicturePile::ApplyInvalidationAndResize(const gfx::Rect& interest_rect, + Region* invalidation, + const gfx::Size& layer_size, + int frame_number, + bool can_use_lcd_text_changed) { bool updated = false; Region synthetic_invalidation; @@ -207,22 +234,17 @@ updated = true; } - gfx::Rect interest_rect = visible_layer_rect; - interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_); - recorded_viewport_ = interest_rect; - recorded_viewport_.Intersect(gfx::Rect(GetSize())); - gfx::Rect interest_rect_over_tiles = tiling_.ExpandRectToTileBounds(interest_rect); - gfx::Size min_tiling_size( - std::min(GetSize().width(), old_tiling_size.width()), - std::min(GetSize().height(), old_tiling_size.height())); - gfx::Size max_tiling_size( - std::max(GetSize().width(), old_tiling_size.width()), - std::max(GetSize().height(), old_tiling_size.height())); - if (old_tiling_size != layer_size) { + gfx::Size min_tiling_size( + std::min(GetSize().width(), old_tiling_size.width()), + std::min(GetSize().height(), old_tiling_size.height())); + gfx::Size max_tiling_size( + std::max(GetSize().width(), old_tiling_size.width()), + std::max(GetSize().height(), old_tiling_size.height())); + has_any_recordings_ = false; // Drop recordings that are outside the new or old layer bounds or that @@ -240,12 +262,10 @@ min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height()); } - for (PictureMap::const_iterator it = picture_map_.begin(); - it != picture_map_.end(); - ++it) { - const PictureMapKey& key = it->first; + for (const auto& key_picture_pair : picture_map_) { + const PictureMapKey& key = key_picture_pair.first; if (key.first < min_toss_x && key.second < min_toss_y) { - has_any_recordings_ |= !!it->second.GetPicture(); + has_any_recordings_ |= !!key_picture_pair.second.GetPicture(); continue; } to_erase.push_back(key); @@ -472,10 +492,16 @@ } invalidation->Union(synthetic_invalidation); + return updated; +} +void PicturePile::GetInvalidTileRects(const gfx::Rect& interest_rect, + Region* invalidation, + const gfx::Rect& visible_layer_rect, + int frame_number, + std::vector<gfx::Rect>* invalid_tiles) { // Make a list of all invalid tiles; we will attempt to // cluster these into multiple invalidation regions. - std::vector<gfx::Rect> invalid_tiles; bool include_borders = true; for (TilingData::Iterator it(&tiling_, interest_rect, include_borders); it; ++it) { @@ -488,7 +514,7 @@ if (info.NeedsRecording(frame_number, distance_to_visible)) { gfx::Rect tile = tiling_.TileBounds(key.first, key.second); - invalid_tiles.push_back(tile); + invalid_tiles->push_back(tile); } else if (!info.GetPicture()) { if (recorded_viewport_.Intersects(rect)) { // Recorded viewport is just an optimization for a fully recorded @@ -504,18 +530,13 @@ invalidation->Union(tiling_.TileBounds(it.index_x(), it.index_y())); } } +} - std::vector<gfx::Rect> record_rects; - ClusterTiles(invalid_tiles, &record_rects); - - if (record_rects.empty()) - return updated; - - for (std::vector<gfx::Rect>::iterator it = record_rects.begin(); - it != record_rects.end(); - it++) { - gfx::Rect record_rect = *it; - record_rect = PadRect(record_rect); +void PicturePile::CreatePictures(ContentLayerClient* painter, + Picture::RecordingMode recording_mode, + const std::vector<gfx::Rect>& record_rects) { + for (const auto& record_rect : record_rects) { + gfx::Rect padded_record_rect = PadRect(record_rect); int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); scoped_refptr<Picture> picture; @@ -526,44 +547,34 @@ // Picture::Create. bool gather_pixel_refs = RasterWorkerPool::GetNumRasterThreads() > 1; - { - for (int i = 0; i < repeat_count; i++) { - picture = Picture::Create(record_rect, - painter, - tile_grid_info_, - gather_pixel_refs, - recording_mode); - // Note the '&&' with previous is-suitable state. - // This means that once a picture-pile becomes unsuitable for gpu - // rasterization due to some content, it will continue to be unsuitable - // even if that content is replaced by gpu-friendly content. - // This is an optimization to avoid iterating though all pictures in - // the pile after each invalidation. - is_suitable_for_gpu_rasterization_ &= - picture->IsSuitableForGpuRasterization(); - } + for (int i = 0; i < repeat_count; i++) { + picture = Picture::Create(padded_record_rect, painter, tile_grid_info_, + gather_pixel_refs, recording_mode); + // Note the '&&' with previous is-suitable state. + // This means that once a picture-pile becomes unsuitable for gpu + // rasterization due to some content, it will continue to be unsuitable + // even if that content is replaced by gpu-friendly content. + // This is an optimization to avoid iterating though all pictures in + // the pile after each invalidation. + is_suitable_for_gpu_rasterization_ &= + picture->IsSuitableForGpuRasterization(); } bool found_tile_for_recorded_picture = false; bool include_borders = true; - for (TilingData::Iterator it(&tiling_, record_rect, include_borders); it; - ++it) { + for (TilingData::Iterator it(&tiling_, padded_record_rect, include_borders); + it; ++it) { const PictureMapKey& key = it.index(); gfx::Rect tile = PaddedRect(key); - if (record_rect.Contains(tile)) { + if (padded_record_rect.Contains(tile)) { PictureInfo& info = picture_map_[key]; info.SetPicture(picture); found_tile_for_recorded_picture = true; } } - DetermineIfSolidColor(); DCHECK(found_tile_for_recorded_picture); } - - has_any_recordings_ = true; - DCHECK(CanRasterSlowTileCheck(recorded_viewport_)); - return true; } scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const {
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h index e1c1b46..fd1c454 100644 --- a/cc/resources/picture_pile.h +++ b/cc/resources/picture_pile.h
@@ -7,6 +7,7 @@ #include <bitset> #include <utility> +#include <vector> #include "base/containers/hash_tables.h" #include "base/memory/ref_counted.h" @@ -106,6 +107,19 @@ private: friend class PicturePileImpl; + void CreatePictures(ContentLayerClient* painter, + Picture::RecordingMode recording_mode, + const std::vector<gfx::Rect>& record_rects); + void GetInvalidTileRects(const gfx::Rect& interest_rect, + Region* invalidation, + const gfx::Rect& visible_layer_rect, + int frame_number, + std::vector<gfx::Rect>* invalid_tiles); + bool ApplyInvalidationAndResize(const gfx::Rect& interest_rect, + Region* invalidation, + const gfx::Size& layer_size, + int frame_number, + bool can_use_lcd_text_changed); void DetermineIfSolidColor(); void SetBufferPixels(int buffer_pixels);
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index 06bb5f0..636e797 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc
@@ -794,9 +794,9 @@ image += source_offset.y() * image_row_bytes + source_offset.x() * 4; ScopedWriteLockSoftware lock(this, id); - SkCanvas* dest = lock.sk_canvas(); - dest->writePixels( - source_info, image, image_row_bytes, dest_offset.x(), dest_offset.y()); + SkCanvas dest(lock.sk_bitmap()); + dest.writePixels(source_info, image, image_row_bytes, dest_offset.x(), + dest_offset.y()); } } @@ -1038,7 +1038,6 @@ resource_(resource_provider->LockForWrite(resource_id)) { ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_); DCHECK(valid()); - sk_canvas_.reset(new SkCanvas(sk_bitmap_)); } ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() { @@ -2077,7 +2076,7 @@ DCHECK(dest_resource->origin == Resource::Internal); DCHECK_EQ(dest_resource->exported_count, 0); DCHECK_EQ(GLTexture, dest_resource->type); - LazyCreate(dest_resource); + LazyAllocate(dest_resource); DCHECK_EQ(source_resource->type, dest_resource->type); DCHECK_EQ(source_resource->format, dest_resource->format);
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h index c2f349f..bfd3ebb 100644 --- a/cc/resources/resource_provider.h +++ b/cc/resources/resource_provider.h
@@ -296,14 +296,13 @@ ResourceProvider::ResourceId resource_id); ~ScopedWriteLockSoftware(); - SkCanvas* sk_canvas() { return sk_canvas_.get(); } + SkBitmap& sk_bitmap() { return sk_bitmap_; } bool valid() const { return !!sk_bitmap_.getPixels(); } private: ResourceProvider* resource_provider_; ResourceProvider::Resource* resource_; SkBitmap sk_bitmap_; - scoped_ptr<SkCanvas> sk_canvas_; base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockSoftware); @@ -599,21 +598,24 @@ DISALLOW_COPY_AND_ASSIGN(ResourceProvider); }; - // TODO(epenner): Move these format conversions to resource_format.h // once that builds on mac (npapi.h currently #includes OpenGL.h). inline unsigned BitsPerPixel(ResourceFormat format) { - DCHECK_LE(format, RESOURCE_FORMAT_MAX); - static const unsigned format_bits_per_pixel[RESOURCE_FORMAT_MAX + 1] = { - 32, // RGBA_8888 - 16, // RGBA_4444 - 32, // BGRA_8888 - 8, // ALPHA_8 - 8, // LUMINANCE_8 - 16, // RGB_565, - 4 // ETC1 - }; - return format_bits_per_pixel[format]; + switch (format) { + case BGRA_8888: + case RGBA_8888: + return 32; + case RGBA_4444: + case RGB_565: + return 16; + case ALPHA_8: + case LUMINANCE_8: + return 8; + case ETC1: + return 4; + } + NOTREACHED(); + return 0; } inline GLenum GLDataType(ResourceFormat format) {
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index d8bfe4c..34b604a 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc
@@ -3416,6 +3416,10 @@ .WillOnce(Return(kDestTextureId)) .RetiresOnSaturation(); EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kDestTextureId)) + .Times(2) + .RetiresOnSaturation(); + EXPECT_CALL(*context, texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*context, NextTextureId())
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc index 01a6042..7a775d9 100644 --- a/cc/resources/video_resource_updater.cc +++ b/cc/resources/video_resource_updater.cc
@@ -249,7 +249,8 @@ { ResourceProvider::ScopedWriteLockSoftware lock( resource_provider_, plane_resources[0].resource_id); - video_renderer_->Copy(video_frame, lock.sk_canvas()); + SkCanvas canvas(lock.sk_bitmap()); + video_renderer_->Copy(video_frame, &canvas); } RecycleResourceData recycle_data = {
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc index dd6cdbe..5252dcc 100644 --- a/cc/scheduler/begin_frame_source.cc +++ b/cc/scheduler/begin_frame_source.cc
@@ -181,10 +181,9 @@ return; base::TimeTicks now = Now(); - BeginFrameArgs args = - BeginFrameArgs::Create(now, - now + BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::DefaultInterval()); + BeginFrameArgs args = BeginFrameArgs::Create( + now, now + BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); CallOnBeginFrame(args); } @@ -243,8 +242,8 @@ base::TimeTicks frame_time, BeginFrameArgs::BeginFrameArgsType type) { base::TimeTicks deadline = time_source_->NextTickTime(); - return BeginFrameArgs::CreateTyped( - frame_time, deadline, time_source_->Interval(), type); + return BeginFrameArgs::Create(frame_time, deadline, time_source_->Interval(), + type); } // TimeSourceClient support
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc index a4b3d6e..498d10b 100644 --- a/cc/scheduler/begin_frame_source_unittest.cc +++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -38,13 +38,13 @@ // Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting // observer behaviour). -#define SEND_BEGIN_FRAME( \ - args_equal_to, source, frame_time, deadline, interval) \ +#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \ + interval) \ { \ BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \ BeginFrameArgs new_args = \ CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \ - ASSERT_TRUE(!(old_args == new_args)); \ + ASSERT_FALSE(old_args == new_args); \ (source).TestOnBeginFrame(new_args); \ EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \ } @@ -494,9 +494,8 @@ TEST_F(SyntheticBeginFrameSourceTest, SetNeedsBeginFramesCallsOnBeginFrameWithMissedTick) { now_src_->SetNowMicroseconds(10010); - EXPECT_CALL((*obs_), - OnBeginFrame(CreateTypedBeginFrameArgsForTesting( - 10000, 20000, 10000, BeginFrameArgs::MISSED))); + EXPECT_CALL((*obs_), OnBeginFrame(CreateBeginFrameArgsForTesting( + 10000, 20000, 10000, BeginFrameArgs::MISSED))); source_->SetNeedsBeginFrames(true); // Should cause the last tick to be sent // No tasks should need to be run for this to occur. }
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index b190988..3e6f6c6 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc
@@ -393,6 +393,21 @@ bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); + // Deliver BeginFrames to children. + if (settings_.forward_begin_frames_to_children && + state_machine_.children_need_begin_frames()) { + BeginFrameArgs adjusted_args_for_children(args); + // Adjust a deadline for child schedulers. + // TODO(simonhong): Once we have commitless update, we can get rid of + // BeginMainFrameToCommitDurationEstimate() + + // CommitToActivateDurationEstimate(). + adjusted_args_for_children.deadline -= + (client_->BeginMainFrameToCommitDurationEstimate() + + client_->CommitToActivateDurationEstimate() + + client_->DrawDurationEstimate() + EstimatedParentDrawTime()); + client_->SendBeginFramesToChildren(adjusted_args_for_children); + } + // We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has // sent us the last BeginFrame we have missed. As we might not be able to // actually make rendering for this call, handle it like a "retro frame". @@ -428,6 +443,12 @@ return true; } +void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { + DCHECK(settings_.forward_begin_frames_to_children); + state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames); + DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE); +} + // BeginRetroFrame is called for BeginFrames that we've deferred because // the scheduler was in the middle of processing a previous BeginFrame. void Scheduler::BeginRetroFrame() {
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index 2a924f1..ef52ccf 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h
@@ -48,6 +48,7 @@ virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() = 0; virtual base::TimeDelta CommitToActivateDurationEstimate() = 0; virtual void DidBeginImplFrameDeadline() = 0; + virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) = 0; protected: virtual ~SchedulerClient() {} @@ -93,6 +94,9 @@ ~Scheduler() override; + // BeginFrameObserverMixin + bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) override; + // base::PowerObserver method. void OnPowerStateChange(bool on_battery_power) override; @@ -164,8 +168,7 @@ state_machine_.SetContinuousPainting(continuous_painting); } - // BeginFrameObserverMixin - bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) override; + void SetChildrenNeedBeginFrames(bool children_need_begin_frames); protected: Scheduler(SchedulerClient* client,
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 82b13d7..5f56255 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc
@@ -47,7 +47,8 @@ skip_next_begin_main_frame_to_reduce_latency_(false), skip_begin_main_frame_to_reduce_latency_(false), continuous_painting_(false), - impl_latency_takes_priority_on_battery_(false) { + impl_latency_takes_priority_on_battery_(false), + children_need_begin_frames_(false) { } const char* SchedulerStateMachine::OutputSurfaceStateToString( @@ -234,6 +235,7 @@ state->SetBoolean("continuous_painting", continuous_painting_); state->SetBoolean("impl_latency_takes_priority_on_battery", impl_latency_takes_priority_on_battery_); + state->SetBoolean("children_need_begin_frames", children_need_begin_frames_); state->EndDictionary(); } @@ -672,16 +674,28 @@ skip_next_begin_main_frame_to_reduce_latency_ = true; } +bool SchedulerStateMachine::BeginFrameNeededForChildren() const { + if (HasInitializedOutputSurface()) + return children_need_begin_frames_; + + return false; +} + bool SchedulerStateMachine::BeginFrameNeeded() const { + if (SupportsProactiveBeginFrame()) { + return (BeginFrameNeededToAnimateOrDraw() || + BeginFrameNeededForChildren() || + ProactiveBeginFrameWanted()); + } + // Proactive BeginFrames are bad for the synchronous compositor because we // have to draw when we get the BeginFrame and could end up drawing many // duplicate frames if our new frame isn't ready in time. // To poll for state with the synchronous compositor without having to draw, // we rely on ShouldPollForAnticipatedDrawTriggers instead. - if (!SupportsProactiveBeginFrame()) - return BeginFrameNeededToAnimateOrDraw(); - - return BeginFrameNeededToAnimateOrDraw() || ProactiveBeginFrameWanted(); + // Synchronous compositor doesn't have a browser. + DCHECK(!children_need_begin_frames_); + return BeginFrameNeededToAnimateOrDraw(); } bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const { @@ -707,6 +721,12 @@ return !settings_.using_synchronous_renderer_compositor; } +void SchedulerStateMachine::SetChildrenNeedBeginFrames( + bool children_need_begin_frames) { + DCHECK(settings_.forward_begin_frames_to_children); + children_need_begin_frames_ = children_need_begin_frames; +} + // These are the cases where we definitely (or almost definitely) have a // new frame to animate and/or draw and can draw. bool SchedulerStateMachine::BeginFrameNeededToAnimateOrDraw() const {
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h index 489ece6..c69c959 100644 --- a/cc/scheduler/scheduler_state_machine.h +++ b/cc/scheduler/scheduler_state_machine.h
@@ -247,8 +247,14 @@ // We should remove it afterwards. std::string GetStatesForDebugging() const; + void SetChildrenNeedBeginFrames(bool children_need_begin_frames); + bool children_need_begin_frames() const { + return children_need_begin_frames_; + } + protected: bool BeginFrameNeededToAnimateOrDraw() const; + bool BeginFrameNeededForChildren() const; bool ProactiveBeginFrameWanted() const; // True if we need to force activations to make forward progress. @@ -316,6 +322,7 @@ bool skip_begin_main_frame_to_reduce_latency_; bool continuous_painting_; bool impl_latency_takes_priority_on_battery_; + bool children_need_begin_frames_; private: DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine);
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc index 85160ed..af6d83a 100644 --- a/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -1823,5 +1823,20 @@ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); } +TEST(SchedulerStateMachineTest, TestForwardBeginFramesToChildren) { + SchedulerSettings settings; + settings.forward_begin_frames_to_children = true; + StateMachine state(settings); + state.SetCanStart(); + state.UpdateState(state.NextAction()); + state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); + state.SetVisible(true); + state.SetCanDraw(true); + + EXPECT_FALSE(state.BeginFrameNeeded()); + state.SetChildrenNeedBeginFrames(true); + EXPECT_TRUE(state.BeginFrameNeeded()); +} + } // namespace } // namespace cc
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 7d61df3..636beb0 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -88,6 +88,7 @@ FakeSchedulerClient() : automatic_swap_ack_(true), + begin_frame_is_sent_to_children_(false), now_src_(TestNowSource::Create()), task_runner_(new OrderedSimpleTaskRunner(now_src_, true)), fake_external_begin_frame_source_(nullptr), @@ -109,6 +110,7 @@ swap_will_happen_if_draw_happens_ = true; num_draws_ = 0; log_anticipated_draw_time_change_ = false; + begin_frame_is_sent_to_children_ = false; } TestScheduler* CreateScheduler(const SchedulerSettings& settings) { @@ -266,12 +268,20 @@ void DidBeginImplFrameDeadline() override {} + void SendBeginFramesToChildren(const BeginFrameArgs& args) override { + begin_frame_is_sent_to_children_ = true; + } + base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) { return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback, base::Unretained(this), state); } + bool begin_frame_is_sent_to_children() const { + return begin_frame_is_sent_to_children_; + } + protected: bool ImplFrameDeadlinePendingCallback(bool state) { return scheduler_->BeginImplFrameDeadlinePending() == state; @@ -282,6 +292,7 @@ bool automatic_swap_ack_; int num_draws_; bool log_anticipated_draw_time_change_; + bool begin_frame_is_sent_to_children_; base::TimeTicks posted_begin_impl_frame_deadline_; std::vector<const char*> actions_; std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat>> states_; @@ -343,6 +354,36 @@ EXPECT_NO_ACTION(client); } +TEST(SchedulerTest, SendBeginFramesToChildren) { + FakeSchedulerClient client; + SchedulerSettings scheduler_settings; + scheduler_settings.use_external_begin_frame_source = true; + scheduler_settings.forward_begin_frames_to_children = true; + TestScheduler* scheduler = client.CreateScheduler(scheduler_settings); + scheduler->SetCanStart(); + scheduler->SetVisible(true); + scheduler->SetCanDraw(true); + + EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); + InitializeOutputSurfaceAndFirstCommit(scheduler, &client); + + client.Reset(); + EXPECT_FALSE(client.begin_frame_is_sent_to_children()); + scheduler->SetNeedsCommit(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client); + client.Reset(); + + scheduler->SetChildrenNeedBeginFrames(true); + + client.AdvanceFrame(); + EXPECT_TRUE(client.begin_frame_is_sent_to_children()); + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); + EXPECT_TRUE(client.needs_begin_frames()); + client.Reset(); +} + TEST(SchedulerTest, RequestCommit) { FakeSchedulerClient client; SchedulerSettings scheduler_settings;
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc index 129a116..a8ae27a 100644 --- a/cc/surfaces/display.cc +++ b/cc/surfaces/display.cc
@@ -11,6 +11,7 @@ #include "cc/output/compositor_frame_ack.h" #include "cc/output/direct_renderer.h" #include "cc/output/gl_renderer.h" +#include "cc/output/renderer_settings.h" #include "cc/output/software_renderer.h" #include "cc/resources/texture_mailbox_deleter.h" #include "cc/surfaces/display_client.h" @@ -24,11 +25,13 @@ Display::Display(DisplayClient* client, SurfaceManager* manager, SharedBitmapManager* bitmap_manager, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + const RendererSettings& settings) : client_(client), manager_(manager), bitmap_manager_(bitmap_manager), gpu_memory_buffer_manager_(gpu_memory_buffer_manager), + settings_(settings), device_scale_factor_(1.f), blocking_main_thread_task_runner_( BlockingTaskRunner::Create(base::MessageLoopProxy::current())), @@ -59,28 +62,18 @@ if (resource_provider_) return; - int highp_threshold_min = 0; - bool use_rgba_4444_texture_format = false; - size_t id_allocation_chunk_size = 1; - scoped_ptr<ResourceProvider> resource_provider = - ResourceProvider::Create(output_surface_.get(), - bitmap_manager_, - gpu_memory_buffer_manager_, - blocking_main_thread_task_runner_.get(), - highp_threshold_min, - use_rgba_4444_texture_format, - id_allocation_chunk_size); + scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create( + output_surface_.get(), bitmap_manager_, gpu_memory_buffer_manager_, + blocking_main_thread_task_runner_.get(), settings_.highp_threshold_min, + settings_.use_rgba_4444_textures, + settings_.texture_id_allocation_chunk_size); if (!resource_provider) return; if (output_surface_->context_provider()) { - scoped_ptr<GLRenderer> renderer = - GLRenderer::Create(this, - &settings_, - output_surface_.get(), - resource_provider.get(), - texture_mailbox_deleter_.get(), - highp_threshold_min); + scoped_ptr<GLRenderer> renderer = GLRenderer::Create( + this, &settings_, output_surface_.get(), resource_provider.get(), + texture_mailbox_deleter_.get(), settings_.highp_threshold_min); if (!renderer) return; renderer_ = renderer.Pass();
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h index 5935534..a0bb62a 100644 --- a/cc/surfaces/display.h +++ b/cc/surfaces/display.h
@@ -24,6 +24,7 @@ class DirectRenderer; class DisplayClient; class OutputSurface; +class RendererSettings; class ResourceProvider; class SharedBitmapManager; class Surface; @@ -42,7 +43,8 @@ Display(DisplayClient* client, SurfaceManager* manager, SharedBitmapManager* bitmap_manager, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager); + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + const RendererSettings& settings); ~Display() override; bool Initialize(scoped_ptr<OutputSurface> output_surface); @@ -90,10 +92,10 @@ SurfaceManager* manager_; SharedBitmapManager* bitmap_manager_; gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_; + RendererSettings settings_; SurfaceId current_surface_id_; gfx::Size current_surface_size_; float device_scale_factor_; - LayerTreeSettings settings_; scoped_ptr<OutputSurface> output_surface_; scoped_ptr<ResourceProvider> resource_provider_; scoped_ptr<SurfaceAggregator> aggregator_;
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc index 588d624..f5689c5 100644 --- a/cc/surfaces/surface_aggregator.cc +++ b/cc/surfaces/surface_aggregator.cc
@@ -163,6 +163,7 @@ } void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad, + float opacity, RenderPass* dest_pass) { SurfaceId surface_id = surface_quad->surface_id; // If this surface's id is already in our referenced set then it creates @@ -227,11 +228,8 @@ copy_pass->transform_to_root_target.ConcatTransform( surface_quad->quadTransform()); - CopyQuadsToPass(source.quad_list, - source.shared_quad_state_list, - gfx::Transform(), - copy_pass.get(), - surface_id); + CopyQuadsToPass(source.quad_list, source.shared_quad_state_list, + gfx::Transform(), 1.f, copy_pass.get(), surface_id); dest_pass_list_->push_back(copy_pass.Pass()); } @@ -242,17 +240,16 @@ const QuadList& quads = last_pass.quad_list; // TODO(jamesr): Make sure clipping is enforced. - CopyQuadsToPass(quads, - last_pass.shared_quad_state_list, + CopyQuadsToPass(quads, last_pass.shared_quad_state_list, surface_quad->quadTransform(), - dest_pass, - surface_id); + surface_quad->opacity() * opacity, dest_pass, surface_id); } else { RenderPassId remapped_pass_id = RemapPassId(last_pass.id, surface_id); SharedQuadState* shared_quad_state = dest_pass->CreateAndAppendSharedQuadState(); shared_quad_state->CopyFrom(surface_quad->shared_quad_state); + shared_quad_state->opacity *= opacity; RenderPassDrawQuad* quad = dest_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); quad->SetNew(shared_quad_state, @@ -300,6 +297,7 @@ const QuadList& source_quad_list, const SharedQuadStateList& source_shared_quad_state_list, const gfx::Transform& content_to_target_transform, + float opacity, RenderPass* dest_pass, SurfaceId surface_id) { const SharedQuadState* last_copied_source_shared_quad_state = NULL; @@ -315,11 +313,12 @@ if (quad->material == DrawQuad::SURFACE_CONTENT) { const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad); - HandleSurfaceQuad(surface_quad, dest_pass); + HandleSurfaceQuad(surface_quad, opacity, dest_pass); } else { if (quad->shared_quad_state != last_copied_source_shared_quad_state) { CopySharedQuadState( quad->shared_quad_state, content_to_target_transform, dest_pass); + dest_pass->shared_quad_state_list.back()->opacity *= opacity; last_copied_source_shared_quad_state = quad->shared_quad_state; } if (quad->material == DrawQuad::RENDER_PASS) { @@ -371,10 +370,8 @@ source.transform_to_root_target, source.has_transparent_background); - CopyQuadsToPass(source.quad_list, - source.shared_quad_state_list, - gfx::Transform(), - copy_pass.get(), + CopyQuadsToPass(source.quad_list, source.shared_quad_state_list, + gfx::Transform(), 1.f, copy_pass.get(), surface->surface_id()); dest_pass_list_->push_back(copy_pass.Pass());
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h index aeeb590..6965041 100644 --- a/cc/surfaces/surface_aggregator.h +++ b/cc/surfaces/surface_aggregator.h
@@ -41,6 +41,7 @@ SurfaceId surface_id); void HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad, + float opacity, RenderPass* dest_pass); void CopySharedQuadState(const SharedQuadState* source_sqs, const gfx::Transform& content_to_target_transform, @@ -48,6 +49,7 @@ void CopyQuadsToPass(const QuadList& source_quad_list, const SharedQuadStateList& source_shared_quad_state_list, const gfx::Transform& content_to_target_transform, + float opacity, RenderPass* dest_pass, SurfaceId surface_id); void CopyPasses(const DelegatedFrameData* frame_data, Surface* surface);
diff --git a/cc/surfaces/surface_aggregator_test_helpers.cc b/cc/surfaces/surface_aggregator_test_helpers.cc index 6b527c0..b21b37e 100644 --- a/cc/surfaces/surface_aggregator_test_helpers.cc +++ b/cc/surfaces/surface_aggregator_test_helpers.cc
@@ -24,13 +24,13 @@ void AddTestSurfaceQuad(TestRenderPass* pass, const gfx::Size& surface_size, + float opacity, SurfaceId surface_id) { gfx::Transform content_to_target_transform; gfx::Size content_bounds = surface_size; gfx::Rect visible_content_rect = gfx::Rect(surface_size); gfx::Rect clip_rect = gfx::Rect(surface_size); bool is_clipped = false; - float opacity = 1.0; SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode; SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState(); @@ -82,7 +82,7 @@ AddQuad(pass, gfx::Rect(0, 0, 5, 5), desc.color); break; case DrawQuad::SURFACE_CONTENT: - AddTestSurfaceQuad(pass, gfx::Size(5, 5), desc.surface_id); + AddTestSurfaceQuad(pass, gfx::Size(5, 5), desc.opacity, desc.surface_id); break; case DrawQuad::RENDER_PASS: AddTestRenderPassQuad(pass, desc.render_pass_id);
diff --git a/cc/surfaces/surface_aggregator_test_helpers.h b/cc/surfaces/surface_aggregator_test_helpers.h index 6f3a342..05c8344 100644 --- a/cc/surfaces/surface_aggregator_test_helpers.h +++ b/cc/surfaces/surface_aggregator_test_helpers.h
@@ -30,9 +30,10 @@ return quad; } - static Quad SurfaceQuad(SurfaceId surface_id) { + static Quad SurfaceQuad(SurfaceId surface_id, float opacity) { Quad quad; quad.material = DrawQuad::SURFACE_CONTENT; + quad.opacity = opacity; quad.surface_id = surface_id; return quad; } @@ -47,6 +48,7 @@ DrawQuad::Material material; // Set when material==DrawQuad::SURFACE_CONTENT. SurfaceId surface_id; + float opacity; // Set when material==DrawQuad::SOLID_COLOR. SkColor color; // Set when material==DrawQuad::RENDER_PASS. @@ -55,6 +57,7 @@ private: Quad() : material(DrawQuad::INVALID), + opacity(1.f), color(SK_ColorWHITE), render_pass_id(-1, -1) {} };
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc index 5213327..2e47708 100644 --- a/cc/surfaces/surface_aggregator_unittest.cc +++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -155,6 +155,88 @@ AggregateAndVerify(passes, arraysize(passes), ids, arraysize(ids)); } +TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) { + SurfaceId embedded_surface_id = allocator_.GenerateId(); + factory_.Create(embedded_surface_id, SurfaceSize()); + + test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)}; + test::Pass embedded_passes[] = { + test::Pass(embedded_quads, arraysize(embedded_quads))}; + + SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); + + test::Quad quads[] = {test::Quad::SurfaceQuad(embedded_surface_id, .5f)}; + test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; + + SubmitFrame(passes, arraysize(passes), root_surface_id_); + + scoped_ptr<CompositorFrame> aggregated_frame = + aggregator_.Aggregate(root_surface_id_); + + ASSERT_TRUE(aggregated_frame); + ASSERT_TRUE(aggregated_frame->delegated_frame_data); + + DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get(); + + RenderPassList& render_pass_list(frame_data->render_pass_list); + ASSERT_EQ(1u, render_pass_list.size()); + SharedQuadStateList& shared_quad_state_list( + render_pass_list[0]->shared_quad_state_list); + ASSERT_EQ(1u, shared_quad_state_list.size()); + EXPECT_EQ(.5f, shared_quad_state_list.ElementAt(0)->opacity); + + factory_.Destroy(embedded_surface_id); +} + +TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCombinedWithNesting) { + SurfaceId surface_id1 = allocator_.GenerateId(); + factory_.Create(surface_id1, SurfaceSize()); + SurfaceId surface_id2 = allocator_.GenerateId(); + factory_.Create(surface_id2, SurfaceSize()); + + // |surface_id1| is color quad. + { + test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)}; + test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; + SubmitFrame(passes, arraysize(passes), surface_id1); + } + + // |surface_id2| has a color quad and a surface quad using |surface_id1| at .5 + // opacity. + { + test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE), + test::Quad::SurfaceQuad(surface_id1, .5f)}; + test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; + SubmitFrame(passes, arraysize(passes), surface_id2); + } + + // Another frame with a surface referencing |surface_id2| @ .6 opacity. + { + test::Quad quads[] = {test::Quad::SurfaceQuad(surface_id2, .6f)}; + test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; + SubmitFrame(passes, arraysize(passes), root_surface_id_); + } + + scoped_ptr<CompositorFrame> aggregated_frame = + aggregator_.Aggregate(root_surface_id_); + + ASSERT_TRUE(aggregated_frame); + ASSERT_TRUE(aggregated_frame->delegated_frame_data); + + DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get(); + + RenderPassList& render_pass_list(frame_data->render_pass_list); + ASSERT_EQ(1u, render_pass_list.size()); + SharedQuadStateList& shared_quad_state_list( + render_pass_list[0]->shared_quad_state_list); + ASSERT_EQ(2u, shared_quad_state_list.size()); + EXPECT_EQ(.6f, shared_quad_state_list.ElementAt(0)->opacity); + EXPECT_EQ(.3f, shared_quad_state_list.ElementAt(1)->opacity); + + factory_.Destroy(surface_id1); + factory_.Destroy(surface_id2); +} + TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) { test::Quad quads[][2] = {{test::Quad::SolidColorQuad(SK_ColorWHITE), test::Quad::SolidColorQuad(SK_ColorLTGRAY)}, @@ -185,7 +267,7 @@ SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE), - test::Quad::SurfaceQuad(embedded_surface_id), + test::Quad::SurfaceQuad(embedded_surface_id, 1.f), test::Quad::SolidColorQuad(SK_ColorBLACK)}; test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; @@ -218,7 +300,7 @@ factory_.RequestCopyOfSurface(embedded_surface_id, copy_request.Pass()); test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE), - test::Quad::SurfaceQuad(embedded_surface_id), + test::Quad::SurfaceQuad(embedded_surface_id, 1.f), test::Quad::SolidColorQuad(SK_ColorBLACK)}; test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; @@ -277,7 +359,7 @@ CopyOutputRequest* copy_request2_ptr = copy_request2.get(); test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE), - test::Quad::SurfaceQuad(embedded_surface_id), + test::Quad::SurfaceQuad(embedded_surface_id, 1.f), test::Quad::SolidColorQuad(SK_ColorBLACK)}; test::Quad root_quads2[] = {test::Quad::SolidColorQuad(SK_ColorRED)}; test::Pass root_passes[] = { @@ -368,7 +450,7 @@ test::Quad root_quads[][2] = { {test::Quad::SolidColorQuad(5), test::Quad::SolidColorQuad(6)}, - {test::Quad::SurfaceQuad(embedded_surface_id), + {test::Quad::SurfaceQuad(embedded_surface_id, 1.f), test::Quad::RenderPassQuad(pass_ids[0])}, {test::Quad::SolidColorQuad(7), test::Quad::RenderPassQuad(pass_ids[1])}}; test::Pass root_passes[] = { @@ -489,7 +571,7 @@ // be dropped. TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) { test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), - test::Quad::SurfaceQuad(InvalidSurfaceId()), + test::Quad::SurfaceQuad(InvalidSurfaceId(), 1.f), test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; @@ -510,7 +592,7 @@ SurfaceId surface_with_no_frame_id = allocator_.GenerateId(); factory_.Create(surface_with_no_frame_id, gfx::Size(5, 5)); test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), - test::Quad::SurfaceQuad(surface_with_no_frame_id), + test::Quad::SurfaceQuad(surface_with_no_frame_id, 1.f), test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; @@ -529,7 +611,7 @@ // Tests a surface quad referencing itself, generating a trivial cycle. // The quad creating the cycle should be dropped from the final frame. TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) { - test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_id_), + test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_id_, 1.f), test::Quad::SolidColorQuad(SK_ColorYELLOW)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; @@ -549,7 +631,7 @@ factory_.Create(child_surface_id, SurfaceSize()); test::Quad parent_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE), - test::Quad::SurfaceQuad(child_surface_id), + test::Quad::SurfaceQuad(child_surface_id, 1.f), test::Quad::SolidColorQuad(SK_ColorCYAN)}; test::Pass parent_passes[] = { test::Pass(parent_quads, arraysize(parent_quads))}; @@ -557,7 +639,7 @@ SubmitFrame(parent_passes, arraysize(parent_passes), root_surface_id_); test::Quad child_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), - test::Quad::SurfaceQuad(root_surface_id_), + test::Quad::SurfaceQuad(root_surface_id_, 1.f), test::Quad::SolidColorQuad(SK_ColorMAGENTA)}; test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))}; @@ -599,7 +681,7 @@ // Pass IDs from the parent surface may collide with ones from the child. RenderPassId parent_pass_id[] = {RenderPassId(2, 1), RenderPassId(1, 2)}; test::Quad parent_quad[][1] = { - {test::Quad::SurfaceQuad(child_surface_id)}, + {test::Quad::SurfaceQuad(child_surface_id, 1.f)}, {test::Quad::RenderPassQuad(parent_pass_id[0])}}; test::Pass parent_passes[] = { test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]), @@ -858,7 +940,7 @@ factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure()); test::Quad root_quads[] = {test::Quad::SolidColorQuad(1), - test::Quad::SurfaceQuad(child_surface_id)}; + test::Quad::SurfaceQuad(child_surface_id, 1.f)}; test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; RenderPassList root_pass_list; @@ -981,7 +1063,7 @@ factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure()); - test::Quad root_quads[] = {test::Quad::SurfaceQuad(child_surface_id)}; + test::Quad root_quads[] = {test::Quad::SurfaceQuad(child_surface_id, 1.f)}; test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; RenderPassList root_pass_list;
diff --git a/cc/test/begin_frame_args_test.cc b/cc/test/begin_frame_args_test.cc index 1c4b236..f70d0c5 100644 --- a/cc/test/begin_frame_args_test.cc +++ b/cc/test/begin_frame_args_test.cc
@@ -16,9 +16,8 @@ BeginFrameArgs CreateBeginFrameArgsForTesting(base::TimeTicks frame_time) { return BeginFrameArgs::Create( - frame_time, - frame_time + (BeginFrameArgs::DefaultInterval() / 2), - BeginFrameArgs::DefaultInterval()); + frame_time, frame_time + (BeginFrameArgs::DefaultInterval() / 2), + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); } BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time, @@ -26,47 +25,47 @@ int64 interval) { return BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(frame_time), base::TimeTicks::FromInternalValue(deadline), - base::TimeDelta::FromInternalValue(interval)); + base::TimeDelta::FromInternalValue(interval), + BeginFrameArgs::NORMAL); } -BeginFrameArgs CreateTypedBeginFrameArgsForTesting( +BeginFrameArgs CreateBeginFrameArgsForTesting( int64 frame_time, int64 deadline, int64 interval, BeginFrameArgs::BeginFrameArgsType type) { - return BeginFrameArgs::CreateTyped( - base::TimeTicks::FromInternalValue(frame_time), - base::TimeTicks::FromInternalValue(deadline), - base::TimeDelta::FromInternalValue(interval), - type); + return BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(frame_time), + base::TimeTicks::FromInternalValue(deadline), + base::TimeDelta::FromInternalValue(interval), + type); } BeginFrameArgs CreateExpiredBeginFrameArgsForTesting() { base::TimeTicks now = gfx::FrameTime::Now(); - return BeginFrameArgs::Create(now, - now - BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::DefaultInterval()); + return BeginFrameArgs::Create(now, now - BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::NORMAL); } BeginFrameArgs CreateBeginFrameArgsForTesting( scoped_refptr<TestNowSource> now_src) { base::TimeTicks now = now_src->Now(); - return BeginFrameArgs::Create(now, - now + (BeginFrameArgs::DefaultInterval() / 2), - BeginFrameArgs::DefaultInterval()); + return BeginFrameArgs::Create( + now, now + (BeginFrameArgs::DefaultInterval() / 2), + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); } BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( scoped_refptr<TestNowSource> now_src) { base::TimeTicks now = now_src->Now(); - return BeginFrameArgs::Create(now, - now - BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::DefaultInterval()); + return BeginFrameArgs::Create(now, now - BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::NORMAL); } bool operator==(const BeginFrameArgs& lhs, const BeginFrameArgs& rhs) { - return (lhs.frame_time == rhs.frame_time) && (lhs.deadline == rhs.deadline) && - (lhs.interval == rhs.interval); + return (lhs.type == rhs.type) && (lhs.frame_time == rhs.frame_time) && + (lhs.deadline == rhs.deadline) && (lhs.interval == rhs.interval); } ::std::ostream& operator<<(::std::ostream& os, const BeginFrameArgs& args) { @@ -75,7 +74,8 @@ } void PrintTo(const BeginFrameArgs& args, ::std::ostream* os) { - *os << "BeginFrameArgs(" << args.frame_time.ToInternalValue() << ", " + *os << "BeginFrameArgs(" << BeginFrameArgs::TypeToString(args.type) << ", " + << args.frame_time.ToInternalValue() << ", " << args.deadline.ToInternalValue() << ", " << args.interval.InMicroseconds() << "us)"; }
diff --git a/cc/test/begin_frame_args_test.h b/cc/test/begin_frame_args_test.h index 425a07b..ca4aa45 100644 --- a/cc/test/begin_frame_args_test.h +++ b/cc/test/begin_frame_args_test.h
@@ -20,7 +20,7 @@ BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time, int64 deadline, int64 interval); -BeginFrameArgs CreateTypedBeginFrameArgsForTesting( +BeginFrameArgs CreateBeginFrameArgsForTesting( int64 frame_time, int64 deadline, int64 interval,
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h index 2bcacd8..5404cb0 100644 --- a/cc/test/fake_proxy.h +++ b/cc/test/fake_proxy.h
@@ -45,6 +45,7 @@ void SetDebugState(const LayerTreeDebugState& debug_state) override {} bool MainFrameWillHappenForTesting() override; void AsValueInto(base::debug::TracedValue* state) const override; + void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override {} virtual RendererCapabilities& GetRendererCapabilities(); void SetMaxPartialTextureUpdates(size_t max);
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc index 4542d2a..9bd75ac 100644 --- a/cc/test/layer_tree_pixel_resource_test.cc +++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -26,13 +26,12 @@ case GL_ZERO_COPY_2D_DRAW: case GL_ZERO_COPY_RECT_DRAW: case GL_ONE_COPY_2D_STAGING_2D_DRAW: + case GL_ONE_COPY_RECT_STAGING_2D_DRAW: case GL_ASYNC_UPLOAD_2D_DRAW: return true; case GL_ZERO_COPY_EXTERNAL_DRAW: - case GL_ONE_COPY_RECT_STAGING_2D_DRAW: case GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW: // These should all be enabled in practice. - // TODO(reveman): one copy with rect not supported in unit tests yet. // TODO(enne): look into getting texture external oes enabled. return false; } @@ -76,7 +75,7 @@ case GL_ONE_COPY_RECT_STAGING_2D_DRAW: test_type_ = PIXEL_TEST_GL; staging_texture_target_ = GL_TEXTURE_RECTANGLE_ARB; - draw_texture_target_ = GL_TEXTURE_RECTANGLE_ARB; + draw_texture_target_ = GL_TEXTURE_2D; resource_pool_option_ = ONE_COPY_RASTER_WORKER_POOL; return; case GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW:
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index a22c7af..80e9f11 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -380,6 +380,10 @@ test_hooks_->DidInitializeOutputSurface(); } + void SendBeginFramesToChildren(const BeginFrameArgs& args) override { + test_hooks_->SendBeginFramesToChildren(args); + } + void DidFailToInitializeOutputSurface() override { test_hooks_->DidFailToInitializeOutputSurface(); } @@ -607,8 +611,8 @@ scoped_ptr<ExternalBeginFrameSourceForTest> external_begin_frame_source; if (settings_.use_external_begin_frame_source && settings_.throttle_frame_production) { - external_begin_frame_source.reset( - new ExternalBeginFrameSourceForTest(settings_.refresh_rate)); + external_begin_frame_source.reset(new ExternalBeginFrameSourceForTest( + settings_.renderer_settings.refresh_rate)); external_begin_frame_source_ = external_begin_frame_source.get(); } @@ -741,7 +745,7 @@ // Spend less time waiting for BeginFrame because the output is // mocked out. - settings_.refresh_rate = 200.0; + settings_.renderer_settings.refresh_rate = 200.0; settings_.background_animation_rate = 200.0; settings_.impl_side_painting = impl_side_painting; InitializeSettings(&settings_);
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h index b801d94..2914cfc 100644 --- a/cc/test/layer_tree_test.h +++ b/cc/test/layer_tree_test.h
@@ -89,6 +89,7 @@ virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl, bool visible) {} virtual void ScheduleComposite() {} + virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) {} // Hooks for SchedulerClient. virtual void ScheduledActionWillSendBeginMainFrame() {}
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index 28c0dc0..76966e9 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -144,12 +144,9 @@ texture_mailbox_deleter_ = make_scoped_ptr( new TextureMailboxDeleter(base::MessageLoopProxy::current())); - renderer_ = GLRenderer::Create(this, - &settings_, - output_surface_.get(), - resource_provider_.get(), - texture_mailbox_deleter_.get(), - 0); + renderer_ = GLRenderer::Create( + this, &settings_.renderer_settings, output_surface_.get(), + resource_provider_.get(), texture_mailbox_deleter_.get(), 0); } void PixelTest::ForceExpandedViewport(const gfx::Size& surface_expansion) { @@ -188,8 +185,9 @@ 0, false, 1); - renderer_ = SoftwareRenderer::Create( - this, &settings_, output_surface_.get(), resource_provider_.get()); + renderer_ = + SoftwareRenderer::Create(this, &settings_.renderer_settings, + output_surface_.get(), resource_provider_.get()); } } // namespace cc
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h index 46cdcba..3c5350c 100644 --- a/cc/test/pixel_test.h +++ b/cc/test/pixel_test.h
@@ -101,7 +101,7 @@ class GLRendererWithExpandedViewport : public GLRenderer { public: GLRendererWithExpandedViewport(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider, TextureMailboxDeleter* texture_mailbox_deleter, @@ -117,7 +117,7 @@ class SoftwareRendererWithExpandedViewport : public SoftwareRenderer { public: SoftwareRendererWithExpandedViewport(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) : SoftwareRenderer(client, settings, output_surface, resource_provider) {} @@ -126,7 +126,7 @@ class GLRendererWithFlippedSurface : public GLRenderer { public: GLRendererWithFlippedSurface(RendererClient* client, - const LayerTreeSettings* settings, + const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider, TextureMailboxDeleter* texture_mailbox_deleter,
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc index 847bc92..34b0493 100644 --- a/cc/test/test_in_process_context_provider.cc +++ b/cc/test/test_in_process_context_provider.cc
@@ -129,7 +129,6 @@ ContextProvider::Capabilities capabilities; capabilities.gpu.image = true; capabilities.gpu.texture_rectangle = true; - capabilities.gpu.sync_query = true; return capabilities; }
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 808bf21..c2fce2a 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -23,6 +23,7 @@ #include "cc/debug/devtools_instrumentation.h" #include "cc/debug/rendering_stats_instrumentation.h" #include "cc/input/layer_selection_bound.h" +#include "cc/input/page_scale_animation.h" #include "cc/input/top_controls_manager.h" #include "cc/layers/heads_up_display_layer.h" #include "cc/layers/heads_up_display_layer_impl.h" @@ -197,7 +198,7 @@ } // We must clear any pointers into the layer tree prior to destroying it. - RegisterViewportLayers(NULL, NULL, NULL); + RegisterViewportLayers(NULL, NULL, NULL, NULL); if (root_layer_.get()) { // The layer tree must be destroyed before the layer tree host. We've @@ -347,11 +348,12 @@ sync_tree->set_has_transparent_background(has_transparent_background_); if (page_scale_layer_.get() && inner_viewport_scroll_layer_.get()) { - sync_tree->SetViewportLayersFromIds(page_scale_layer_->id(), - inner_viewport_scroll_layer_->id(), - outer_viewport_scroll_layer_.get() - ? outer_viewport_scroll_layer_->id() - : Layer::INVALID_ID); + sync_tree->SetViewportLayersFromIds( + overscroll_elasticity_layer_.get() ? overscroll_elasticity_layer_->id() + : Layer::INVALID_ID, + page_scale_layer_->id(), inner_viewport_scroll_layer_->id(), + outer_viewport_scroll_layer_.get() ? outer_viewport_scroll_layer_->id() + : Layer::INVALID_ID); } else { sync_tree->ClearViewportLayers(); } @@ -381,12 +383,8 @@ host_impl->SetDeviceScaleFactor(device_scale_factor_); host_impl->SetDebugState(debug_state_); if (pending_page_scale_animation_) { - sync_tree->SetPageScaleAnimation( - pending_page_scale_animation_->target_offset, - pending_page_scale_animation_->use_anchor, - pending_page_scale_animation_->scale, - pending_page_scale_animation_->duration); - pending_page_scale_animation_ = nullptr; + sync_tree->SetPendingPageScaleAnimation( + pending_page_scale_animation_.Pass()); } if (!ui_resource_request_queue_.empty()) { @@ -724,11 +722,12 @@ bool use_anchor, float scale, base::TimeDelta duration) { - pending_page_scale_animation_.reset(new PendingPageScaleAnimation); - pending_page_scale_animation_->target_offset = target_offset; - pending_page_scale_animation_->use_anchor = use_anchor; - pending_page_scale_animation_->scale = scale; - pending_page_scale_animation_->duration = duration; + pending_page_scale_animation_.reset( + new PendingPageScaleAnimation( + target_offset, + use_anchor, + scale, + duration)); SetNeedsCommit(); } @@ -1288,9 +1287,11 @@ } void LayerTreeHost::RegisterViewportLayers( + scoped_refptr<Layer> overscroll_elasticity_layer, scoped_refptr<Layer> page_scale_layer, scoped_refptr<Layer> inner_viewport_scroll_layer, scoped_refptr<Layer> outer_viewport_scroll_layer) { + overscroll_elasticity_layer_ = overscroll_elasticity_layer; page_scale_layer_ = page_scale_layer; inner_viewport_scroll_layer_ = inner_viewport_scroll_layer; outer_viewport_scroll_layer_ = outer_viewport_scroll_layer; @@ -1352,4 +1353,14 @@ return SurfaceSequence(surface_id_namespace_, next_surface_sequence_++); } +void LayerTreeHost::SetChildrenNeedBeginFrames( + bool children_need_begin_frames) const { + proxy_->SetChildrenNeedBeginFrames(children_need_begin_frames); +} + +void LayerTreeHost::SendBeginFramesToChildren( + const BeginFrameArgs& args) const { + client_->SendBeginFramesToChildren(args); +} + } // namespace cc
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index 7820cc2..de91b76 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -63,6 +63,7 @@ class SharedBitmapManager; class TopControlsManager; class UIResourceRequest; +struct PendingPageScaleAnimation; struct RenderingStats; struct ScrollAndScaleSet; @@ -179,11 +180,14 @@ void SetRootLayer(scoped_refptr<Layer> root_layer); Layer* root_layer() { return root_layer_.get(); } const Layer* root_layer() const { return root_layer_.get(); } + const Layer* overscroll_elasticity_layer() const { + return overscroll_elasticity_layer_.get(); + } const Layer* page_scale_layer() const { return page_scale_layer_.get(); } - void RegisterViewportLayers( - scoped_refptr<Layer> page_scale_layer, - scoped_refptr<Layer> inner_viewport_scroll_layer, - scoped_refptr<Layer> outer_viewport_scroll_layer); + void RegisterViewportLayers(scoped_refptr<Layer> overscroll_elasticity_layer, + scoped_refptr<Layer> page_scale_layer, + scoped_refptr<Layer> inner_viewport_scroll_layer, + scoped_refptr<Layer> outer_viewport_scroll_layer); Layer* inner_viewport_scroll_layer() const { return inner_viewport_scroll_layer_.get(); } @@ -314,6 +318,9 @@ void set_surface_id_namespace(uint32_t id_namespace); SurfaceSequence CreateSurfaceSequence(); + void SetChildrenNeedBeginFrames(bool children_need_begin_frames) const; + void SendBeginFramesToChildren(const BeginFrameArgs& args) const; + protected: LayerTreeHost(LayerTreeHostClient* client, SharedBitmapManager* shared_bitmap_manager, @@ -433,12 +440,6 @@ scoped_ptr<AnimationRegistrar> animation_registrar_; - struct PendingPageScaleAnimation { - gfx::Vector2d target_offset; - bool use_anchor; - float scale; - base::TimeDelta duration; - }; scoped_ptr<PendingPageScaleAnimation> pending_page_scale_animation_; bool in_paint_layer_contents_; @@ -460,6 +461,7 @@ int id_; bool next_commit_forces_redraw_; + scoped_refptr<Layer> overscroll_elasticity_layer_; scoped_refptr<Layer> page_scale_layer_; scoped_refptr<Layer> inner_viewport_scroll_layer_; scoped_refptr<Layer> outer_viewport_scroll_layer_;
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h index dca389d..5b02964 100644 --- a/cc/trees/layer_tree_host_client.h +++ b/cc/trees/layer_tree_host_client.h
@@ -45,6 +45,10 @@ virtual void DidCommitAndDrawFrame() = 0; virtual void DidCompleteSwapBuffers() = 0; + // TODO(simonhong): Makes this to pure virtual function when client + // implementation is ready. + virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) {} + // Requests that the client insert a rate limiting token in the shared main // thread context's command stream that will block if the context gets too far // ahead of the compositor's command stream. Only needed if the tree contains
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index bb1be98..e49dcfe 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -414,6 +414,48 @@ client_->DidManageTiles(); } +void LayerTreeHostImpl::StartPageScaleAnimation( + const gfx::Vector2d& target_offset, + bool anchor_point, + float page_scale, + base::TimeDelta duration) { + if (!InnerViewportScrollLayer()) + return; + + gfx::ScrollOffset scroll_total = active_tree_->TotalScrollOffset(); + gfx::SizeF scaled_scrollable_size = active_tree_->ScrollableSize(); + gfx::SizeF viewport_size = + active_tree_->InnerViewportContainerLayer()->bounds(); + + // Easing constants experimentally determined. + scoped_ptr<TimingFunction> timing_function = + CubicBezierTimingFunction::Create(.8, 0, .3, .9); + + // TODO(miletus) : Pass in ScrollOffset. + page_scale_animation_ = + PageScaleAnimation::Create(ScrollOffsetToVector2dF(scroll_total), + active_tree_->total_page_scale_factor(), + viewport_size, + scaled_scrollable_size, + timing_function.Pass()); + + if (anchor_point) { + gfx::Vector2dF anchor(target_offset); + page_scale_animation_->ZoomWithAnchor(anchor, + page_scale, + duration.InSecondsF()); + } else { + gfx::Vector2dF scaled_target_offset = target_offset; + page_scale_animation_->ZoomTo(scaled_target_offset, + page_scale, + duration.InSecondsF()); + } + + SetNeedsAnimate(); + client_->SetNeedsCommitOnImplThread(); + client_->RenewTreePriority(); +} + bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt( const gfx::Point& viewport_point, InputHandler::ScrollInputType type) { @@ -1514,7 +1556,8 @@ IsActivelyScrolling() || needs_animate_layers(); scoped_ptr<SoftwareRenderer> temp_software_renderer = - SoftwareRenderer::Create(this, &settings_, output_surface_.get(), NULL); + SoftwareRenderer::Create(this, &settings_.renderer_settings, + output_surface_.get(), NULL); temp_software_renderer->DrawFrame(&frame->render_passes, device_scale_factor_, DeviceViewport(), @@ -1807,13 +1850,14 @@ stats.draw_duration.GetLastTimeDelta()); } - scoped_ptr<PageScaleAnimation> page_scale_animation = - active_tree_->TakePageScaleAnimation(); - if (page_scale_animation) { - page_scale_animation_ = page_scale_animation.Pass(); - SetNeedsAnimate(); - client_->SetNeedsCommitOnImplThread(); - client_->RenewTreePriority(); + scoped_ptr<PendingPageScaleAnimation> pending_page_scale_animation = + active_tree_->TakePendingPageScaleAnimation(); + if (pending_page_scale_animation) { + StartPageScaleAnimation( + pending_page_scale_animation->target_offset, + pending_page_scale_animation->use_anchor, + pending_page_scale_animation->scale, + pending_page_scale_animation->duration); } } @@ -1896,18 +1940,18 @@ DCHECK(resource_provider_); if (output_surface_->capabilities().delegated_rendering) { - renderer_ = DelegatingRenderer::Create( - this, &settings_, output_surface_.get(), resource_provider_.get()); + renderer_ = DelegatingRenderer::Create(this, &settings_.renderer_settings, + output_surface_.get(), + resource_provider_.get()); } else if (output_surface_->context_provider()) { - renderer_ = GLRenderer::Create(this, - &settings_, - output_surface_.get(), - resource_provider_.get(), - texture_mailbox_deleter_.get(), - settings_.highp_threshold_min); + renderer_ = GLRenderer::Create( + this, &settings_.renderer_settings, output_surface_.get(), + resource_provider_.get(), texture_mailbox_deleter_.get(), + settings_.renderer_settings.highp_threshold_min); } else if (output_surface_->software_device()) { - renderer_ = SoftwareRenderer::Create( - this, &settings_, output_surface_.get(), resource_provider_.get()); + renderer_ = SoftwareRenderer::Create(this, &settings_.renderer_settings, + output_surface_.get(), + resource_provider_.get()); } DCHECK(renderer_); @@ -2026,12 +2070,11 @@ resource_provider_->memory_efficient_texture_format()); *raster_worker_pool = PixelBufferRasterWorkerPool::Create( - task_runner, - RasterWorkerPool::GetTaskGraphRunner(), - context_provider, + task_runner, RasterWorkerPool::GetTaskGraphRunner(), context_provider, resource_provider_.get(), - GetMaxTransferBufferUsageBytes(context_provider->ContextCapabilities(), - settings_.refresh_rate)); + GetMaxTransferBufferUsageBytes( + context_provider->ContextCapabilities(), + settings_.renderer_settings.refresh_rate)); } } @@ -2058,9 +2101,7 @@ } bool LayerTreeHostImpl::CanUseOneCopyRasterizer() const { - // Sync query support is required by one-copy rasterizer. - return GetRendererCapabilities().using_image && - resource_provider_->use_sync_query(); + return GetRendererCapabilities().using_image; } void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) { @@ -2086,14 +2127,12 @@ return false; output_surface_ = output_surface.Pass(); - resource_provider_ = - ResourceProvider::Create(output_surface_.get(), - shared_bitmap_manager_, - gpu_memory_buffer_manager_, - proxy_->blocking_main_thread_task_runner(), - settings_.highp_threshold_min, - settings_.use_rgba_4444_textures, - settings_.texture_id_allocation_chunk_size); + resource_provider_ = ResourceProvider::Create( + output_surface_.get(), shared_bitmap_manager_, gpu_memory_buffer_manager_, + proxy_->blocking_main_thread_task_runner(), + settings_.renderer_settings.highp_threshold_min, + settings_.renderer_settings.use_rgba_4444_textures, + settings_.renderer_settings.texture_id_allocation_chunk_size); if (output_surface_->capabilities().deferred_gl_initialization) EnforceZeroBudget(true); @@ -2105,8 +2144,9 @@ // Initialize vsync parameters to sane values. const base::TimeDelta display_refresh_interval = - base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond / - settings_.refresh_rate); + base::TimeDelta::FromMicroseconds( + base::Time::kMicrosecondsPerSecond / + settings_.renderer_settings.refresh_rate); CommitVSyncParameters(base::TimeTicks(), display_refresh_interval); // TODO(brianderson): Don't use a hard-coded parent draw time. @@ -2633,40 +2673,49 @@ } } + // Scrolls should bubble perfectly between the outer and inner viewports. + bool allow_unrestricted_bubbling_for_current_layer = + layer_impl == OuterViewportScrollLayer(); + bool allow_bubbling_for_current_layer = + allow_unrestricted_bubbling_for_current_layer || should_bubble_scrolls_; + // If the layer wasn't able to move, try the next one in the hierarchy. bool did_move_layer_x = std::abs(applied_delta.x()) > kEpsilon; bool did_move_layer_y = std::abs(applied_delta.y()) > kEpsilon; did_scroll_x |= did_move_layer_x; did_scroll_y |= did_move_layer_y; if (!did_move_layer_x && !did_move_layer_y) { - // Scrolls should always bubble between the outer and inner viewports - if (should_bubble_scrolls_ || !did_lock_scrolling_layer_ || - layer_impl == OuterViewportScrollLayer()) + if (allow_bubbling_for_current_layer || !did_lock_scrolling_layer_) continue; else break; } did_lock_scrolling_layer_ = true; - if (!should_bubble_scrolls_) { + if (!allow_bubbling_for_current_layer) { active_tree_->SetCurrentlyScrollingLayer(layer_impl); break; } - // If the applied delta is within 45 degrees of the input delta, bail out to - // make it easier to scroll just one layer in one direction without - // affecting any of its parents. - float angle_threshold = 45; - if (MathUtil::SmallestAngleBetweenVectors( - applied_delta, pending_delta) < angle_threshold) { - pending_delta = gfx::Vector2dF(); - break; - } + if (allow_unrestricted_bubbling_for_current_layer) { + pending_delta -= applied_delta; + } else { + // If the applied delta is within 45 degrees of the input delta, bail out + // to make it easier to scroll just one layer in one direction without + // affecting any of its parents. + float angle_threshold = 45; + if (MathUtil::SmallestAngleBetweenVectors(applied_delta, pending_delta) < + angle_threshold) { + pending_delta = gfx::Vector2dF(); + break; + } - // Allow further movement only on an axis perpendicular to the direction in - // which the layer moved. - gfx::Vector2dF perpendicular_axis(-applied_delta.y(), applied_delta.x()); - pending_delta = MathUtil::ProjectVector(pending_delta, perpendicular_axis); + // Allow further movement only on an axis perpendicular to the direction + // in which the layer moved. + gfx::Vector2dF perpendicular_axis(-applied_delta.y(), applied_delta.x()); + pending_delta = + MathUtil::ProjectVector(pending_delta, perpendicular_axis); + } if (gfx::ToRoundedVector2d(pending_delta).IsZero()) break; @@ -3202,9 +3251,9 @@ // task), fall back to physical time. This should still be monotonic. if (current_begin_frame_args_.IsValid()) return current_begin_frame_args_; - return BeginFrameArgs::Create(gfx::FrameTime::Now(), - base::TimeTicks(), - BeginFrameArgs::DefaultInterval()); + return BeginFrameArgs::Create(gfx::FrameTime::Now(), base::TimeTicks(), + BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::NORMAL); } scoped_refptr<base::debug::ConvertableToTraceFormat>
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index ba4fabf..d1b29ca 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -146,6 +146,10 @@ void PinchGestureUpdate(float magnify_delta, const gfx::Point& anchor) override; void PinchGestureEnd() override; + void StartPageScaleAnimation(const gfx::Vector2d& target_offset, + bool anchor_point, + float page_scale, + base::TimeDelta duration); void SetNeedsAnimate() override; bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point, InputHandler::ScrollInputType type) override;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 51377d2..7151689 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -96,7 +96,7 @@ LayerTreeSettings settings; settings.minimum_occlusion_tracking_size = gfx::Size(); settings.impl_side_painting = true; - settings.texture_id_allocation_chunk_size = 1; + settings.renderer_settings.texture_id_allocation_chunk_size = 1; settings.report_overscroll_only_for_scrollable_axes = true; settings.use_pinch_virtual_viewport = true; return settings; @@ -256,7 +256,8 @@ layer_tree_impl->SetRootLayer(root.Pass()); layer_tree_impl->SetViewportLayersFromIds( - kPageScaleLayerId, kInnerViewportScrollLayerId, Layer::INVALID_ID); + Layer::INVALID_ID, kPageScaleLayerId, kInnerViewportScrollLayerId, + Layer::INVALID_ID); return scroll_layer; } @@ -1159,11 +1160,12 @@ did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->active_tree()->SetPageScaleAnimation( - gfx::Vector2d(), - false, - 2.f, - duration); + host_impl_->active_tree()->SetPendingPageScaleAnimation( + scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation( + gfx::Vector2d(), + false, + 2.f, + duration))); host_impl_->ActivateSyncTree(); EXPECT_FALSE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); @@ -1202,8 +1204,12 @@ did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->active_tree()->SetPageScaleAnimation( - gfx::Vector2d(25, 25), true, min_page_scale, duration); + host_impl_->active_tree()->SetPendingPageScaleAnimation( + scoped_ptr<PendingPageScaleAnimation> (new PendingPageScaleAnimation( + gfx::Vector2d(25, 25), + true, + min_page_scale, + duration))); host_impl_->ActivateSyncTree(); EXPECT_FALSE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); @@ -1253,11 +1259,12 @@ max_page_scale); scroll_layer->SetScrollOffset(gfx::ScrollOffset(50, 50)); - host_impl_->active_tree()->SetPageScaleAnimation( - gfx::Vector2d(), - true, - 1.f, - duration); + host_impl_->active_tree()->SetPendingPageScaleAnimation( + scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation( + gfx::Vector2d(), + true, + 1.f, + duration))); host_impl_->ActivateSyncTree(); host_impl_->Animate(start_time); host_impl_->Animate(halfway_through_animation); @@ -1301,26 +1308,29 @@ scroll_layer->SetScrollOffset(gfx::ScrollOffset(50, 50)); // Make sure TakePageScaleAnimation works properly. - host_impl_->sync_tree()->SetPageScaleAnimation( - gfx::Vector2d(), - false, - target_scale, - duration); - scoped_ptr<PageScaleAnimation> psa = - host_impl_->sync_tree()->TakePageScaleAnimation(); - EXPECT_EQ(target_scale, psa->target_page_scale_factor()); - EXPECT_EQ(duration, psa->duration()); - EXPECT_EQ(nullptr, host_impl_->sync_tree()->TakePageScaleAnimation()); + + host_impl_->sync_tree()->SetPendingPageScaleAnimation( + scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation( + gfx::Vector2d(), + false, + target_scale, + duration))); + scoped_ptr<PendingPageScaleAnimation> psa = + host_impl_->sync_tree()->TakePendingPageScaleAnimation(); + EXPECT_EQ(target_scale, psa->scale); + EXPECT_EQ(duration, psa->duration); + EXPECT_EQ(nullptr, host_impl_->sync_tree()->TakePendingPageScaleAnimation()); // Recreate the PSA. Nothing should happen here since the tree containing the // PSA hasn't been activated yet. did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->sync_tree()->SetPageScaleAnimation( - gfx::Vector2d(), - false, - target_scale, - duration); + host_impl_->sync_tree()->SetPendingPageScaleAnimation( + scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation( + gfx::Vector2d(), + false, + target_scale, + duration))); host_impl_->Animate(halfway_through_animation); EXPECT_FALSE(did_request_animate_); EXPECT_FALSE(did_request_redraw_); @@ -1328,7 +1338,8 @@ // Activate the sync tree. This should cause the animation to become enabled. // It should also clear the pointer on the sync tree. host_impl_->ActivateSyncTree(); - EXPECT_EQ(nullptr, host_impl_->sync_tree()->TakePageScaleAnimation().get()); + EXPECT_EQ(nullptr, + host_impl_->sync_tree()->TakePendingPageScaleAnimation().get()); EXPECT_FALSE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); @@ -1395,53 +1406,51 @@ base::TimeTicks fake_current_physical_time_; }; -#define SETUP_LAYERS_FOR_SCROLLBAR_ANIMATION_TEST() \ - gfx::Size viewport_size(10, 10); \ - gfx::Size content_size(100, 100); \ - \ - LayerTreeHostImplOverridePhysicalTime* host_impl_override_time = \ - new LayerTreeHostImplOverridePhysicalTime(settings, \ - this, \ - &proxy_, \ - shared_bitmap_manager_.get(), \ - &stats_instrumentation_); \ - host_impl_ = make_scoped_ptr(host_impl_override_time); \ - host_impl_->InitializeRenderer(CreateOutputSurface()); \ - host_impl_->SetViewportSize(viewport_size); \ - \ - scoped_ptr<LayerImpl> root = \ - LayerImpl::Create(host_impl_->active_tree(), 1); \ - root->SetBounds(viewport_size); \ - \ - scoped_ptr<LayerImpl> scroll = \ - LayerImpl::Create(host_impl_->active_tree(), 2); \ - scroll->SetScrollClipLayer(root->id()); \ - scroll->SetScrollOffset(gfx::ScrollOffset()); \ - root->SetBounds(viewport_size); \ - scroll->SetBounds(content_size); \ - scroll->SetContentBounds(content_size); \ - scroll->SetIsContainerForFixedPositionLayers(true); \ - \ - scoped_ptr<LayerImpl> contents = \ - LayerImpl::Create(host_impl_->active_tree(), 3); \ - contents->SetDrawsContent(true); \ - contents->SetBounds(content_size); \ - contents->SetContentBounds(content_size); \ - \ - scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar = \ - SolidColorScrollbarLayerImpl::Create( \ - host_impl_->active_tree(), 4, VERTICAL, 10, 0, false, true); \ - EXPECT_FLOAT_EQ(0.f, scrollbar->opacity()); \ - \ - scroll->AddChild(contents.Pass()); \ - root->AddChild(scroll.Pass()); \ - scrollbar->SetScrollLayerAndClipLayerByIds(2, 1); \ - root->AddChild(scrollbar.Pass()); \ - \ - host_impl_->active_tree()->SetRootLayer(root.Pass()); \ - host_impl_->active_tree()->SetViewportLayersFromIds( \ - 1, 2, Layer::INVALID_ID); \ - host_impl_->active_tree()->DidBecomeActive(); \ +#define SETUP_LAYERS_FOR_SCROLLBAR_ANIMATION_TEST() \ + gfx::Size viewport_size(10, 10); \ + gfx::Size content_size(100, 100); \ + \ + LayerTreeHostImplOverridePhysicalTime* host_impl_override_time = \ + new LayerTreeHostImplOverridePhysicalTime(settings, this, &proxy_, \ + shared_bitmap_manager_.get(), \ + &stats_instrumentation_); \ + host_impl_ = make_scoped_ptr(host_impl_override_time); \ + host_impl_->InitializeRenderer(CreateOutputSurface()); \ + host_impl_->SetViewportSize(viewport_size); \ + \ + scoped_ptr<LayerImpl> root = \ + LayerImpl::Create(host_impl_->active_tree(), 1); \ + root->SetBounds(viewport_size); \ + \ + scoped_ptr<LayerImpl> scroll = \ + LayerImpl::Create(host_impl_->active_tree(), 2); \ + scroll->SetScrollClipLayer(root->id()); \ + scroll->SetScrollOffset(gfx::ScrollOffset()); \ + root->SetBounds(viewport_size); \ + scroll->SetBounds(content_size); \ + scroll->SetContentBounds(content_size); \ + scroll->SetIsContainerForFixedPositionLayers(true); \ + \ + scoped_ptr<LayerImpl> contents = \ + LayerImpl::Create(host_impl_->active_tree(), 3); \ + contents->SetDrawsContent(true); \ + contents->SetBounds(content_size); \ + contents->SetContentBounds(content_size); \ + \ + scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar = \ + SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), 4, \ + VERTICAL, 10, 0, false, true); \ + EXPECT_FLOAT_EQ(0.f, scrollbar->opacity()); \ + \ + scroll->AddChild(contents.Pass()); \ + root->AddChild(scroll.Pass()); \ + scrollbar->SetScrollLayerAndClipLayerByIds(2, 1); \ + root->AddChild(scrollbar.Pass()); \ + \ + host_impl_->active_tree()->SetRootLayer(root.Pass()); \ + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2, \ + Layer::INVALID_ID); \ + host_impl_->active_tree()->DidBecomeActive(); \ DrawFrame(); TEST_F(LayerTreeHostImplTest, ScrollbarLinearFadeScheduling) { @@ -1608,7 +1617,8 @@ root->AddChild(scrollbar.Pass()); host_impl_->active_tree()->SetRootLayer(root.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); @@ -2282,7 +2292,8 @@ root_clip->AddChild(root.Pass()); host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); host_impl_->active_tree()->SetViewportLayersFromIds( - page_scale_layer_id, inner_viewport_scroll_layer_id, Layer::INVALID_ID); + Layer::INVALID_ID, page_scale_layer_id, inner_viewport_scroll_layer_id, + Layer::INVALID_ID); // Set a viewport size that is large enough to contain both the top controls // and some content. host_impl_->SetViewportSize(viewport_size_); @@ -2306,7 +2317,8 @@ root_clip->AddChild(root.Pass()); host_impl_->sync_tree()->SetRootLayer(root_clip.Pass()); host_impl_->sync_tree()->SetViewportLayersFromIds( - page_scale_layer_id, inner_viewport_scroll_layer_id, Layer::INVALID_ID); + Layer::INVALID_ID, page_scale_layer_id, inner_viewport_scroll_layer_id, + Layer::INVALID_ID); // Set a viewport size that is large enough to contain both the top controls // and some content. host_impl_->SetViewportSize(viewport_size_); @@ -2361,8 +2373,7 @@ host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); host_impl_->active_tree()->SetViewportLayersFromIds( - page_scale_layer_id, - inner_viewport_scroll_layer_id, + Layer::INVALID_ID, page_scale_layer_id, inner_viewport_scroll_layer_id, outer_viewport_scroll_layer_id); host_impl_->SetViewportSize(inner_viewport_size); @@ -2986,7 +2997,8 @@ host_impl_->active_tree()->SetRootLayer(root.Pass()); // The behaviour in this test assumes the page scale is applied at a layer // above the clip layer. - host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 3, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(viewport_size); DrawFrame(); @@ -3036,7 +3048,8 @@ host_impl_->active_tree()->SetRootLayer(root.Pass()); // The behaviour in this test assumes the page scale is applied at a layer // above the clip layer. - host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 3, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(viewport_size); host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale); @@ -3151,7 +3164,8 @@ LayerImpl* child = child_scrolling.get(); root_scrolling_ptr->AddChild(child_scrolling.Pass()); host_impl_->active_tree()->SetRootLayer(root.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); DrawFrame(); @@ -3254,7 +3268,8 @@ root->AddChild(root_scrolling.Pass()); EXPECT_EQ(viewport_size, root->bounds()); host_impl_->active_tree()->SetRootLayer(root.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(viewport_size); @@ -3360,7 +3375,8 @@ host_impl_->SetViewportSize(surface_size); host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(3, 2, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 2, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -3389,7 +3405,8 @@ root_scroll->SetIsContainerForFixedPositionLayers(true); root_clip->AddChild(root_scroll.Pass()); host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); @@ -3404,7 +3421,8 @@ root_scroll2->SetIsContainerForFixedPositionLayers(true); root_clip2->AddChild(root_scroll2.Pass()); host_impl_->active_tree()->SetRootLayer(root_clip2.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(3, 4, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 4, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); // Scrolling should still work even though we did not draw yet. @@ -3992,7 +4010,8 @@ host_impl_->SetViewportSize(surface_size); host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -4051,7 +4070,8 @@ host_impl_->SetViewportSize(surface_size); host_impl_->SetDeviceScaleFactor(device_scale_factor); host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -4085,7 +4105,8 @@ host_impl_->SetViewportSize(surface_size); host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -4795,7 +4816,7 @@ // This test creates its own LayerTreeHostImpl, so // that we can force partial swap enabled. LayerTreeSettings settings; - settings.partial_swap_enabled = true; + settings.renderer_settings.partial_swap_enabled = true; scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl = @@ -5011,7 +5032,7 @@ // Run test case LayerTreeSettings settings = DefaultSettings(); - settings.partial_swap_enabled = false; + settings.renderer_settings.partial_swap_enabled = false; CreateHostImpl(settings, FakeOutputSurface::Create3d(mock_context_owned.Pass())); SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1)); @@ -5047,7 +5068,7 @@ MockContextHarness harness(mock_context); LayerTreeSettings settings = DefaultSettings(); - settings.partial_swap_enabled = true; + settings.renderer_settings.partial_swap_enabled = true; CreateHostImpl(settings, FakeOutputSurface::Create3d(context_owned.Pass())); SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1)); @@ -5091,7 +5112,7 @@ provider->TestContext3d()->set_have_post_sub_buffer(true); LayerTreeSettings settings; - settings.partial_swap_enabled = partial_swap; + settings.renderer_settings.partial_swap_enabled = partial_swap; scoped_ptr<LayerTreeHostImpl> my_host_impl = LayerTreeHostImpl::Create( settings, client, proxy, stats_instrumentation, manager, NULL, 0); my_host_impl->InitializeRenderer(output_surface.Pass()); @@ -5264,7 +5285,7 @@ // Run test case LayerTreeSettings settings = DefaultSettings(); - settings.partial_swap_enabled = false; + settings.renderer_settings.partial_swap_enabled = false; CreateHostImpl(settings, FakeOutputSurface::Create3d(mock_context_owned.Pass())); SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1)); @@ -6630,7 +6651,8 @@ host_impl_->SetViewportSize(surface_size); host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID); + host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1, + Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -7472,8 +7494,9 @@ inner_clip->AddChild(page_scale.Pass()); layer_tree_impl->SetRootLayer(inner_clip.Pass()); - layer_tree_impl->SetViewportLayersFromIds(kPageScaleLayerId, - kInnerViewportScrollLayerId, kOuterViewportScrollLayerId); + layer_tree_impl->SetViewportLayersFromIds( + Layer::INVALID_ID, kPageScaleLayerId, kInnerViewportScrollLayerId, + kOuterViewportScrollLayerId); host_impl_->active_tree()->DidBecomeActive(); } @@ -7527,6 +7550,49 @@ } } +TEST_F(LayerTreeHostImplVirtualViewportTest, + DiagonalScrollBubblesPerfectlyToInner) { + gfx::Size content_size = gfx::Size(100, 160); + gfx::Size outer_viewport = gfx::Size(50, 80); + gfx::Size inner_viewport = gfx::Size(25, 40); + + SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport); + + LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer(); + LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer(); + DrawFrame(); + { + gfx::Vector2dF inner_expected; + gfx::Vector2dF outer_expected; + EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset()); + EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset()); + + // Make sure the scroll goes to the outer viewport first. + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); + EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin()); + + // Scroll near the edge of the outer viewport. + gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height()); + host_impl_->ScrollBy(gfx::Point(), scroll_delta); + outer_expected += scroll_delta; + + EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset()); + EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset()); + + // Now diagonal scroll across the outer viewport boundary in a single event. + // The entirety of the scroll should be consumed, as bubbling between inner + // and outer viewport layers is perfect. + host_impl_->ScrollBy(gfx::Point(), gfx::ScaleVector2d(scroll_delta, 2)); + outer_expected += scroll_delta; + inner_expected += scroll_delta; + host_impl_->ScrollEnd(); + + EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset()); + EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset()); + } +} + class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest { public: void SetUp() override {
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc index 14029b5..aa236c8 100644 --- a/cc/trees/layer_tree_host_pixeltest_blending.cc +++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -62,8 +62,9 @@ } void InitializeSettings(LayerTreeSettings* settings) override { - settings->force_antialiasing = force_antialiasing_; - settings->force_blending_with_shaders = force_blending_with_shaders_; + settings->renderer_settings.force_antialiasing = force_antialiasing_; + settings->renderer_settings.force_blending_with_shaders = + force_blending_with_shaders_; } protected:
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc index 4d0717d..c494914 100644 --- a/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -51,6 +51,9 @@ gfx::Size bounds_; }; +// TODO(enne): these time out on Windows. http://crbug.com/435632 +#if !defined(OS_WIN) + TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayer) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( gfx::Rect(200, 200), SK_ColorWHITE); @@ -272,6 +275,8 @@ "mask_of_replica_of_clipped_layer.png"))); } +#endif // !defined(OS_WIN) + } // namespace } // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 72a5b45..f589c84 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1018,8 +1018,8 @@ layer_tree_host()->root_layer()->AddChild(scroll_layer_); // This test requires the page_scale and inner viewport layers to be // identified. - layer_tree_host()->RegisterViewportLayers( - root_layer, scroll_layer_.get(), NULL); + layer_tree_host()->RegisterViewportLayers(NULL, root_layer, + scroll_layer_.get(), NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f); } @@ -1308,7 +1308,7 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest { public: void InitializeSettings(LayerTreeSettings* settings) override { - settings->texture_id_allocation_chunk_size = 1; + settings->renderer_settings.texture_id_allocation_chunk_size = 1; // Make sure partial texture updates are turned off. settings->max_partial_texture_updates = 0; // Linear fade animator prevents scrollbars from drawing immediately. @@ -1485,7 +1485,7 @@ : public LayerTreeHostTest { public: void InitializeSettings(LayerTreeSettings* settings) override { - settings->texture_id_allocation_chunk_size = 1; + settings->renderer_settings.texture_id_allocation_chunk_size = 1; // Allow one partial texture update. settings->max_partial_texture_updates = 1; // No partial updates when impl side painting is enabled. @@ -2980,7 +2980,7 @@ LayerTreeHostTestUIResource() : num_ui_resources_(0) {} void InitializeSettings(LayerTreeSettings* settings) override { - settings->texture_id_allocation_chunk_size = 1; + settings->renderer_settings.texture_id_allocation_chunk_size = 1; } void BeginTest() override { PostSetNeedsCommitToMainThread(); } @@ -5140,7 +5140,7 @@ base::Unretained(this))); // Wait 50x longer than expected. double milliseconds_per_frame = - 1000.0 / layer_tree_host()->settings().refresh_rate; + 1000.0 / layer_tree_host()->settings().renderer_settings.refresh_rate; MainThreadTaskRunner()->PostDelayedTask( FROM_HERE, base::Bind( @@ -5197,6 +5197,82 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousPainting); +class LayerTreeHostTestSendBeginFramesToChildren : public LayerTreeHostTest { + public: + LayerTreeHostTestSendBeginFramesToChildren() + : begin_frame_sent_to_children_(false) { + } + + void InitializeSettings(LayerTreeSettings* settings) override { + settings->forward_begin_frames_to_children = true; + } + + void BeginTest() override { + // Kick off the test with a commit. + PostSetNeedsCommitToMainThread(); + } + + void SendBeginFramesToChildren(const BeginFrameArgs& args) override { + begin_frame_sent_to_children_ = true; + EndTest(); + } + + void DidBeginMainFrame() override { + // Children requested BeginFrames. + layer_tree_host()->SetChildrenNeedBeginFrames(true); + } + + void AfterTest() override { + // Ensure that BeginFrame message is sent to children during parent + // scheduler handles its BeginFrame. + EXPECT_TRUE(begin_frame_sent_to_children_); + } + + private: + bool begin_frame_sent_to_children_; +}; + +SINGLE_THREAD_TEST_F(LayerTreeHostTestSendBeginFramesToChildren); + +class LayerTreeHostTestSendBeginFramesToChildrenWithExternalBFS + : public LayerTreeHostTest { + public: + LayerTreeHostTestSendBeginFramesToChildrenWithExternalBFS() + : begin_frame_sent_to_children_(false) { + } + + void InitializeSettings(LayerTreeSettings* settings) override { + settings->use_external_begin_frame_source = true; + settings->forward_begin_frames_to_children = true; + } + + void BeginTest() override { + // Kick off the test with a commit. + PostSetNeedsCommitToMainThread(); + } + + void SendBeginFramesToChildren(const BeginFrameArgs& args) override { + begin_frame_sent_to_children_ = true; + EndTest(); + } + + void DidBeginMainFrame() override { + // Children requested BeginFrames. + layer_tree_host()->SetChildrenNeedBeginFrames(true); + } + + void AfterTest() override { + // Ensure that BeginFrame message is sent to children during parent + // scheduler handles its BeginFrame. + EXPECT_TRUE(begin_frame_sent_to_children_); + } + + private: + bool begin_frame_sent_to_children_; +}; + +SINGLE_THREAD_TEST_F(LayerTreeHostTestSendBeginFramesToChildrenWithExternalBFS); + class LayerTreeHostTestActivateOnInvisible : public LayerTreeHostTest { public: LayerTreeHostTestActivateOnInvisible() @@ -5412,7 +5488,7 @@ layer->disable_lcd_text(); pinch->AddChild(layer); - layer_tree_host()->RegisterViewportLayers(root, pinch, pinch); + layer_tree_host()->RegisterViewportLayers(NULL, root, pinch, pinch); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f); layer_tree_host()->SetRootLayer(root); LayerTreeHostTest::SetupTree(); @@ -5622,7 +5698,7 @@ layer->disable_lcd_text(); pinch->AddChild(layer); - layer_tree_host()->RegisterViewportLayers(root, pinch, pinch); + layer_tree_host()->RegisterViewportLayers(NULL, root, pinch, pinch); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f); layer_tree_host()->SetRootLayer(root); LayerTreeHostTest::SetupTree();
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc index dc34d3c..b646e6a 100644 --- a/cc/trees/layer_tree_host_unittest_context.cc +++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -1247,7 +1247,7 @@ public: UIResourceLostTest() : time_step_(0) {} void InitializeSettings(LayerTreeSettings* settings) override { - settings->texture_id_allocation_chunk_size = 1; + settings->renderer_settings.texture_id_allocation_chunk_size = 1; } void BeginTest() override { PostSetNeedsCommitToMainThread(); } void AfterTest() override {}
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index 6526ff8..8015bda 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -45,7 +45,8 @@ scroll_layer->SetIsContainerForFixedPositionLayers(true); scroll_layer->SetScrollClipLayerId(root_layer->id()); scroll_layer->SetScrollOffset(initial_scroll_); - layer_tree_host()->RegisterViewportLayers(root_layer, scroll_layer, NULL); + layer_tree_host()->RegisterViewportLayers(NULL, root_layer, scroll_layer, + NULL); PostSetNeedsCommitToMainThread(); } @@ -122,7 +123,8 @@ scroll_layer_->SetIsContainerForFixedPositionLayers(true); scroll_layer_->SetScrollClipLayerId(root_layer->id()); scroll_layer_->SetScrollOffset(initial_scroll_); - layer_tree_host()->RegisterViewportLayers(root_layer, scroll_layer_, NULL); + layer_tree_host()->RegisterViewportLayers(NULL, root_layer, scroll_layer_, + NULL); PostSetNeedsCommitToMainThread(); } @@ -224,8 +226,8 @@ root_scroll_layer->SetIsContainerForFixedPositionLayers(true); root_layer->AddChild(root_scroll_layer); - layer_tree_host()->RegisterViewportLayers( - root_layer, root_scroll_layer, NULL); + layer_tree_host()->RegisterViewportLayers(NULL, root_layer, + root_scroll_layer, NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } @@ -407,8 +409,8 @@ root_scroll_layer->SetIsContainerForFixedPositionLayers(true); root_layer->AddChild(root_scroll_layer); - layer_tree_host()->RegisterViewportLayers( - root_layer, root_scroll_layer, NULL); + layer_tree_host()->RegisterViewportLayers(NULL, root_layer, + root_scroll_layer, NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } @@ -510,8 +512,8 @@ expected_scroll_layer_->SetScrollOffset(initial_offset_); layer_tree_host()->SetRootLayer(root_layer); - layer_tree_host()->RegisterViewportLayers( - root_layer, root_scroll_layer_, NULL); + layer_tree_host()->RegisterViewportLayers(NULL, root_layer, + root_scroll_layer_, NULL); LayerTreeHostScrollTest::SetupTree(); } @@ -779,8 +781,8 @@ root_scroll_layer->SetIsContainerForFixedPositionLayers(true); root_layer->AddChild(root_scroll_layer); - layer_tree_host()->RegisterViewportLayers( - root_layer, root_scroll_layer, NULL); + layer_tree_host()->RegisterViewportLayers(NULL, root_layer, + root_scroll_layer, NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } @@ -910,8 +912,8 @@ root_scroll_layer->SetIsContainerForFixedPositionLayers(true); root_layer->AddChild(root_scroll_layer); - layer_tree_host()->RegisterViewportLayers( - root_layer, root_scroll_layer, NULL); + layer_tree_host()->RegisterViewportLayers(NULL, root_layer, + root_scroll_layer, NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); }
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index c005a18..ad355fa 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -221,12 +221,14 @@ target_tree->page_scale_delta() / target_tree->sent_page_scale_delta()); target_tree->set_sent_page_scale_delta(1); - target_tree->page_scale_animation_ = page_scale_animation_.Pass(); + target_tree->pending_page_scale_animation_ = + pending_page_scale_animation_.Pass(); if (page_scale_layer_ && inner_viewport_scroll_layer_) { target_tree->SetViewportLayersFromIds( - page_scale_layer_->id(), - inner_viewport_scroll_layer_->id(), + overscroll_elasticity_layer_ ? overscroll_elasticity_layer_->id() + : Layer::INVALID_ID, + page_scale_layer_->id(), inner_viewport_scroll_layer_->id(), outer_viewport_scroll_layer_ ? outer_viewport_scroll_layer_->id() : Layer::INVALID_ID); } else { @@ -425,9 +427,11 @@ } void LayerTreeImpl::SetViewportLayersFromIds( + int overscroll_elasticity_layer_id, int page_scale_layer_id, int inner_viewport_scroll_layer_id, int outer_viewport_scroll_layer_id) { + overscroll_elasticity_layer_ = LayerById(overscroll_elasticity_layer_id); page_scale_layer_ = LayerById(page_scale_layer_id); DCHECK(page_scale_layer_); @@ -1480,45 +1484,14 @@ return proxy()->blocking_main_thread_task_runner(); } -void LayerTreeImpl::SetPageScaleAnimation( - const gfx::Vector2d& target_offset, - bool anchor_point, - float page_scale, - base::TimeDelta duration) { - if (!InnerViewportScrollLayer()) - return; - - gfx::ScrollOffset scroll_total = TotalScrollOffset(); - gfx::SizeF scaled_scrollable_size = ScrollableSize(); - gfx::SizeF viewport_size = InnerViewportContainerLayer()->bounds(); - - // Easing constants experimentally determined. - scoped_ptr<TimingFunction> timing_function = - CubicBezierTimingFunction::Create(.8, 0, .3, .9); - - // TODO(miletus) : Pass in ScrollOffset. - page_scale_animation_ = - PageScaleAnimation::Create(ScrollOffsetToVector2dF(scroll_total), - total_page_scale_factor(), - viewport_size, - scaled_scrollable_size, - timing_function.Pass()); - - if (anchor_point) { - gfx::Vector2dF anchor(target_offset); - page_scale_animation_->ZoomWithAnchor(anchor, - page_scale, - duration.InSecondsF()); - } else { - gfx::Vector2dF scaled_target_offset = target_offset; - page_scale_animation_->ZoomTo(scaled_target_offset, - page_scale, - duration.InSecondsF()); - } +void LayerTreeImpl::SetPendingPageScaleAnimation( + scoped_ptr<PendingPageScaleAnimation> pending_animation) { + pending_page_scale_animation_ = pending_animation.Pass(); } -scoped_ptr<PageScaleAnimation> LayerTreeImpl::TakePageScaleAnimation() { - return page_scale_animation_.Pass(); +scoped_ptr<PendingPageScaleAnimation> + LayerTreeImpl::TakePendingPageScaleAnimation() { + return pending_page_scale_animation_.Pass(); } } // namespace cc
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index 57e6ca1..60a097d 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -44,6 +44,7 @@ class ResourceProvider; class TileManager; class UIResourceRequest; +struct PendingPageScaleAnimation; struct RendererCapabilities; struct SelectionHandle; @@ -137,10 +138,14 @@ void SetCurrentlyScrollingLayer(LayerImpl* layer); void ClearCurrentlyScrollingLayer(); - void SetViewportLayersFromIds(int page_scale_layer_id, + void SetViewportLayersFromIds(int overscroll_elasticity_layer, + int page_scale_layer_id, int inner_viewport_scroll_layer_id, int outer_viewport_scroll_layer_id); void ClearViewportLayers(); + LayerImpl* overscroll_elasticity_layer() { + return overscroll_elasticity_layer_; + } LayerImpl* page_scale_layer() { return page_scale_layer_; } void ApplySentScrollAndScaleDeltasFromAbortedCommit(); void ApplyScrollDeltasSinceBeginMainFrame(); @@ -310,12 +315,9 @@ return top_controls_content_offset_ + top_controls_delta_; } - void SetPageScaleAnimation( - const gfx::Vector2d& target_offset, - bool anchor_point, - float page_scale, - base::TimeDelta duration); - scoped_ptr<PageScaleAnimation> TakePageScaleAnimation(); + void SetPendingPageScaleAnimation( + scoped_ptr<PendingPageScaleAnimation> pending_animation); + scoped_ptr<PendingPageScaleAnimation> TakePendingPageScaleAnimation(); protected: explicit LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl); @@ -334,6 +336,7 @@ SkColor background_color_; bool has_transparent_background_; + LayerImpl* overscroll_elasticity_layer_; LayerImpl* page_scale_layer_; LayerImpl* inner_viewport_scroll_layer_; LayerImpl* outer_viewport_scroll_layer_; @@ -387,7 +390,7 @@ float top_controls_delta_; float sent_top_controls_delta_; - scoped_ptr<PageScaleAnimation> page_scale_animation_; + scoped_ptr<PendingPageScaleAnimation> pending_page_scale_animation_; private: DISALLOW_COPY_AND_ASSIGN(LayerTreeImpl);
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc index f8de8b0..52f8e0a 100644 --- a/cc/trees/layer_tree_impl_unittest.cc +++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -1798,7 +1798,8 @@ host_impl().active_tree()->SetPageScaleFactorAndLimits( page_scale_factor, page_scale_factor, page_scale_factor); host_impl().active_tree()->SetRootLayer(root.Pass()); - host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID); + host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1, + Layer::INVALID_ID); host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); // Sanity check the scenario we just created. @@ -2301,7 +2302,8 @@ host_impl().active_tree()->SetPageScaleFactorAndLimits( page_scale_factor, page_scale_factor, page_scale_factor); host_impl().active_tree()->SetRootLayer(root.Pass()); - host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID); + host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1, + Layer::INVALID_ID); host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); // Sanity check the scenario we just created.
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc index 14c1def..e792427 100644 --- a/cc/trees/layer_tree_settings.cc +++ b/cc/trees/layer_tree_settings.cc
@@ -14,9 +14,6 @@ LayerTreeSettings::LayerTreeSettings() : impl_side_painting(false), - allow_antialiasing(true), - force_antialiasing(false), - force_blending_with_shaders(false), throttle_frame_production(true), single_thread_proxy_scheduler(true), use_external_begin_frame_source(false), @@ -26,11 +23,9 @@ disable_hi_res_timer_tasks_on_battery(false), report_overscroll_only_for_scrollable_axes(false), per_tile_painting_enabled(false), - partial_swap_enabled(false), accelerated_animation_enabled(true), can_use_lcd_text(true), use_distance_field_text(false), - should_clear_root_render_pass(true), gpu_rasterization_enabled(false), gpu_rasterization_forced(false), create_low_res_tiling(false), @@ -49,7 +44,6 @@ top_controls_height(0.f), top_controls_show_threshold(0.5f), top_controls_hide_threshold(0.5f), - refresh_rate(60.0), background_animation_rate(1.0), max_partial_texture_updates(std::numeric_limits<size_t>::max()), default_tile_size(gfx::Size(256, 256)), @@ -64,13 +58,10 @@ skewport_extrapolation_limit_in_content_pixels(2000), max_unused_resource_memory_percentage(100), max_memory_for_prepaint_percentage(100), - highp_threshold_min(0), strict_layer_property_change_checking(false), use_one_copy(false), use_zero_copy(false), ignore_root_layer_flings(false), - use_rgba_4444_textures(false), - texture_id_allocation_chunk_size(64), scheduled_raster_task_limit(32), use_occlusion_for_tile_prioritization(false), record_full_layer(false) {
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h index 69ac995..ebbe7f7 100644 --- a/cc/trees/layer_tree_settings.h +++ b/cc/trees/layer_tree_settings.h
@@ -8,6 +8,7 @@ #include "base/basictypes.h" #include "cc/base/cc_export.h" #include "cc/debug/layer_tree_debug_state.h" +#include "cc/output/renderer_settings.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/size.h" @@ -18,10 +19,8 @@ LayerTreeSettings(); ~LayerTreeSettings(); + RendererSettings renderer_settings; bool impl_side_painting; - bool allow_antialiasing; - bool force_antialiasing; - bool force_blending_with_shaders; bool throttle_frame_production; bool single_thread_proxy_scheduler; bool use_external_begin_frame_source; @@ -31,11 +30,9 @@ bool disable_hi_res_timer_tasks_on_battery; bool report_overscroll_only_for_scrollable_axes; bool per_tile_painting_enabled; - bool partial_swap_enabled; bool accelerated_animation_enabled; bool can_use_lcd_text; bool use_distance_field_text; - bool should_clear_root_render_pass; bool gpu_rasterization_enabled; bool gpu_rasterization_forced; bool create_low_res_tiling; @@ -60,7 +57,6 @@ float top_controls_height; float top_controls_show_threshold; float top_controls_hide_threshold; - double refresh_rate; double background_animation_rate; size_t max_partial_texture_updates; gfx::Size default_tile_size; @@ -74,13 +70,10 @@ int skewport_extrapolation_limit_in_content_pixels; size_t max_unused_resource_memory_percentage; size_t max_memory_for_prepaint_percentage; - int highp_threshold_min; bool strict_layer_property_change_checking; bool use_one_copy; bool use_zero_copy; bool ignore_root_layer_flings; - bool use_rgba_4444_textures; - size_t texture_id_allocation_chunk_size; size_t scheduled_raster_task_limit; bool use_occlusion_for_tile_prioritization; bool record_full_layer;
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h index feeab43..c6f281b 100644 --- a/cc/trees/proxy.h +++ b/cc/trees/proxy.h
@@ -104,6 +104,8 @@ virtual void SetDebugState(const LayerTreeDebugState& debug_state) = 0; + virtual void SetChildrenNeedBeginFrames(bool children_need_begin_frames) = 0; + // Testing hooks virtual bool MainFrameWillHappenForTesting() = 0;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 4cb0a9e..5a40d7e 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -103,7 +103,7 @@ } void SingleThreadProxy::SetVisible(bool visible) { - TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible"); + TRACE_EVENT1("cc", "SingleThreadProxy::SetVisible", "visible", visible); DebugScopedSetImplThread impl(this); layer_tree_host_impl_->SetVisible(visible); if (scheduler_on_impl_thread_) @@ -492,10 +492,9 @@ } { - BeginFrameArgs begin_frame_args( - BeginFrameArgs::Create(frame_begin_time, - base::TimeTicks(), - BeginFrameArgs::DefaultInterval())); + BeginFrameArgs begin_frame_args(BeginFrameArgs::Create( + frame_begin_time, base::TimeTicks(), BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::SYNCHRONOUS)); DoBeginMainFrame(begin_frame_args); DoCommit(); @@ -634,6 +633,12 @@ return false; } +void SingleThreadProxy::SetChildrenNeedBeginFrames( + bool children_need_begin_frames) { + scheduler_on_impl_thread_->SetChildrenNeedBeginFrames( + children_need_begin_frames); +} + void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) { layer_tree_host_impl_->WillBeginImplFrame(args); } @@ -792,4 +797,8 @@ layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame(); } +void SingleThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) { + layer_tree_host_->SendBeginFramesToChildren(args); +} + } // namespace cc
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index e4cf793..3eba6bb 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h
@@ -59,6 +59,7 @@ bool SupportsImplScrolling() const override; void AsValueInto(base::debug::TracedValue* state) const override; bool MainFrameWillHappenForTesting() override; + void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override; // SchedulerClient implementation void WillBeginImplFrame(const BeginFrameArgs& args) override; @@ -75,6 +76,7 @@ base::TimeDelta BeginMainFrameToCommitDurationEstimate() override; base::TimeDelta CommitToActivateDurationEstimate() override; void DidBeginImplFrameDeadline() override; + void SendBeginFramesToChildren(const BeginFrameArgs& args) override; // LayerTreeHostImplClient implementation void UpdateRendererCapabilitiesOnImplThread() override;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc index bd85f01..4793cc5 100644 --- a/cc/trees/thread_proxy.cc +++ b/cc/trees/thread_proxy.cc
@@ -165,7 +165,7 @@ } void ThreadProxy::SetVisible(bool visible) { - TRACE_EVENT0("cc", "ThreadProxy::SetVisible"); + TRACE_EVENT1("cc", "ThreadProxy::SetVisible", "visible", visible); DebugScopedSetMainThreadBlocked main_thread_blocked(this); CompletionEvent completion; @@ -180,7 +180,7 @@ void ThreadProxy::SetVisibleOnImplThread(CompletionEvent* completion, bool visible) { - TRACE_EVENT0("cc", "ThreadProxy::SetVisibleOnImplThread"); + TRACE_EVENT1("cc", "ThreadProxy::SetVisibleOnImplThread", "visible", visible); impl().layer_tree_host_impl->SetVisible(visible); impl().scheduler->SetVisible(visible); completion->Signal(); @@ -1095,6 +1095,10 @@ impl().layer_tree_host_impl->ResetCurrentBeginFrameArgsForNextFrame(); } +void ThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) { + NOTREACHED() << "Only used by SingleThreadProxy"; +} + void ThreadProxy::ReadyToFinalizeTextureUpdates() { DCHECK(IsImplThread()); impl().scheduler->NotifyReadyToCommit(); @@ -1250,6 +1254,10 @@ return main_frame_will_happen; } +void ThreadProxy::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { + NOTREACHED() << "Only used by SingleThreadProxy"; +} + void ThreadProxy::MainFrameWillHappenOnImplThreadForTesting( CompletionEvent* completion, bool* main_frame_will_happen) {
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h index a1064ab..d6d53a8 100644 --- a/cc/trees/thread_proxy.h +++ b/cc/trees/thread_proxy.h
@@ -175,6 +175,7 @@ void SetDebugState(const LayerTreeDebugState& debug_state) override; void AsValueInto(base::debug::TracedValue* value) const override; bool MainFrameWillHappenForTesting() override; + void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override; // LayerTreeHostImplClient implementation void UpdateRendererCapabilitiesOnImplThread() override; @@ -222,6 +223,7 @@ base::TimeDelta BeginMainFrameToCommitDurationEstimate() override; base::TimeDelta CommitToActivateDurationEstimate() override; void DidBeginImplFrameDeadline() override; + void SendBeginFramesToChildren(const BeginFrameArgs& args) override; // ResourceUpdateControllerClient implementation void ReadyToFinalizeTextureUpdates() override;
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h index a4017ec..6a31b8f 100644 --- a/gpu/GLES2/gl2extchromium.h +++ b/gpu/GLES2/gl2extchromium.h
@@ -200,7 +200,7 @@ #ifndef GL_GET_ERROR_QUERY_CHROMIUM // TODO(gman): Get official numbers for this constants. -#define GL_GET_ERROR_QUERY_CHROMIUM 0x84F3 +#define GL_GET_ERROR_QUERY_CHROMIUM 0x6003 #endif #endif /* GL_CHROMIUM_get_error_query */ @@ -256,7 +256,7 @@ #ifndef GL_COMMANDS_ISSUED_CHROMIUM // TODO(gman): Get official numbers for this constants. -#define GL_COMMANDS_ISSUED_CHROMIUM 0x84F2 +#define GL_COMMANDS_ISSUED_CHROMIUM 0x6004 #endif #endif /* GL_CHROMIUM_command_buffer_query */ @@ -367,10 +367,10 @@ #define GL_CHROMIUM_async_pixel_transfers 1 #ifndef GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM -#define GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM 0x84F5 +#define GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM 0x6005 #endif #ifndef GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM -#define GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM 0x84F6 +#define GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM 0x6006 #endif #endif /* GL_CHROMIUM_async_pixel_transfers */ @@ -455,7 +455,7 @@ #ifndef GL_LATENCY_QUERY_CHROMIUM // TODO(gman): Get official numbers for these constants. -#define GL_LATENCY_QUERY_CHROMIUM 0x84F4 +#define GL_LATENCY_QUERY_CHROMIUM 0x6007 #endif #endif /* GL_CHROMIUM_command_buffer_latency_query */
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 226cb73..7cccd43 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -8309,8 +8309,14 @@ if m: name = m.group(1) value = m.group(2) - if len(value) <= 10 and not value in dict: - dict[value] = name + if len(value) <= 10: + if not value in dict: + dict[value] = name + # check our own _CHROMIUM macro conflicts with khronos GL headers. + elif dict[value] != name and (name.endswith('_CHROMIUM') or + dict[value].endswith('_CHROMIUM')): + self.Error("code collision: %s and %s have the same code %s" % + (dict[value], name, value)) file = CHeaderWriter(filename) file.Write("static const GLES2Util::EnumToString "
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index e7118e8..51c6370 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -210,8 +210,11 @@ WaitForCmd(); query_tracker_.reset(); - if (support_client_side_arrays_) + // GLES2Implementation::Initialize() could fail before allocating + // reserved_ids_, so we need delete them carefully. + if (support_client_side_arrays_ && reserved_ids_[0]) { DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]); + } // Release any per-context data in share group. share_group_->FreeContext(this);
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 5c944a8..87aaeb1 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -93,7 +93,8 @@ CommandBuffer* command_buffer, unsigned int size, unsigned int result_size, - unsigned int alignment) + unsigned int alignment, + bool initialize_fail) : command_buffer_(command_buffer), size_(size), result_size_(result_size), @@ -102,7 +103,8 @@ expected_buffer_index_(0), last_alloc_(NULL), expected_offset_(result_size), - actual_offset_(result_size) { + actual_offset_(result_size), + initialize_fail_(initialize_fail) { // We have to allocate the buffers here because // we need to know their address before GLES2Implementation::Initialize // is called. @@ -220,6 +222,7 @@ void* last_alloc_; uint32 expected_offset_; uint32 actual_offset_; + bool initialize_fail_; DISALLOW_COPY_AND_ASSIGN(MockTransferBuffer); }; @@ -234,7 +237,7 @@ // Just check they match. return size_ == starting_buffer_size && result_size_ == result_size && - alignment_ == alignment; + alignment_ == alignment && !initialize_fail_; }; int MockTransferBuffer::GetShmId() { @@ -394,7 +397,8 @@ bool Initialize(ShareGroup* share_group, bool bind_generates_resource_client, bool bind_generates_resource_service, - bool lose_context_when_out_of_memory) { + bool lose_context_when_out_of_memory, + bool transfer_buffer_initialize_fail) { command_buffer_.reset(new StrictMock<MockClientCommandBuffer>()); if (!command_buffer_->Initialize()) return false; @@ -403,7 +407,8 @@ new MockTransferBuffer(command_buffer_.get(), kTransferBufferSize, GLES2Implementation::kStartingOffset, - GLES2Implementation::kAlignment)); + GLES2Implementation::kAlignment, + transfer_buffer_initialize_fail)); helper_.reset(new GLES2CmdHelper(command_buffer())); helper_->Initialize(kCommandBufferSizeBytes); @@ -522,11 +527,13 @@ ContextInitOptions() : bind_generates_resource_client(true), bind_generates_resource_service(true), - lose_context_when_out_of_memory(false) {} + lose_context_when_out_of_memory(false), + transfer_buffer_initialize_fail(false) {} bool bind_generates_resource_client; bool bind_generates_resource_service; bool lose_context_when_out_of_memory; + bool transfer_buffer_initialize_fail; }; bool Initialize(const ContextInitOptions& init_options) { @@ -538,7 +545,8 @@ share_group_.get(), init_options.bind_generates_resource_client, init_options.bind_generates_resource_service, - init_options.lose_context_when_out_of_memory)) + init_options.lose_context_when_out_of_memory, + init_options.transfer_buffer_initialize_fail)) success = false; } @@ -3302,6 +3310,12 @@ EXPECT_FALSE(Initialize(init_options)); } +TEST_F(GLES2ImplementationManualInitTest, FailInitOnTransferBufferFail) { + ContextInitOptions init_options; + init_options.transfer_buffer_initialize_fail = true; + EXPECT_FALSE(Initialize(init_options)); +} + #include "gpu/command_buffer/client/gles2_implementation_unittest_autogen.h" } // namespace gles2
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h index 1a0945a..3176cc8 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -449,6 +449,10 @@ "GL_TIME_ELAPSED_EXT", }, { + 0x6003, + "GL_GET_ERROR_QUERY_CHROMIUM", + }, + { 0x0C10, "GL_SCISSOR_BOX", }, @@ -1089,6 +1093,10 @@ "GL_RGBA32F_EXT", }, { + 0x6004, + "GL_COMMANDS_ISSUED_CHROMIUM", + }, + { 0x813D, "GL_TEXTURE_MAX_LEVEL_APPLE", }, @@ -1126,7 +1134,7 @@ }, { 0x84F5, - "GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM", + "GL_TEXTURE_RECTANGLE_ARB", }, { 0x882A, @@ -1142,7 +1150,7 @@ }, { 0x84F6, - "GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM", + "GL_TEXTURE_BINDING_RECTANGLE_ARB", }, { 0x80AB, @@ -1153,6 +1161,10 @@ "GL_MAX_PATCH_VERTICES_EXT", }, { + 0x6005, + "GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM", + }, + { 0x9105, "GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES", }, @@ -1193,6 +1205,10 @@ "GL_ISOLINES_EXT", }, { + 0x6006, + "GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM", + }, + { 0x8A4A, "GL_SKIP_DECODE_EXT", }, @@ -1221,6 +1237,10 @@ "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT", }, { + 0x6007, + "GL_LATENCY_QUERY_CHROMIUM", + }, + { 0x8916, "GL_GEOMETRY_LINKED_VERTICES_OUT_EXT", },
diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc index 5c24eb0..bef0089 100644 --- a/gpu/command_buffer/service/buffer_manager_unittest.cc +++ b/gpu/command_buffer/service/buffer_manager_unittest.cc
@@ -210,21 +210,21 @@ TEST_F(BufferManagerTest, GetRange) { const GLuint kClientBufferId = 1; const GLuint kServiceBufferId = 11; - const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + const GLsizeiptr kDataSize = 10; manager_->CreateBuffer(kClientBufferId, kServiceBufferId); Buffer* buffer = manager_->GetBuffer(kClientBufferId); ASSERT_TRUE(buffer != NULL); manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER); - DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); + DoBufferData(buffer, kDataSize, GL_STATIC_DRAW, NULL, GL_NO_ERROR); const char* buf = - static_cast<const char*>(buffer->GetRange(0, sizeof(data))); + static_cast<const char*>(buffer->GetRange(0, kDataSize)); ASSERT_TRUE(buf != NULL); const char* buf1 = - static_cast<const char*>(buffer->GetRange(1, sizeof(data) - 1)); + static_cast<const char*>(buffer->GetRange(1, kDataSize - 1)); EXPECT_EQ(buf + 1, buf1); - EXPECT_TRUE(buffer->GetRange(sizeof(data), 1) == NULL); - EXPECT_TRUE(buffer->GetRange(0, sizeof(data) + 1) == NULL); - EXPECT_TRUE(buffer->GetRange(-1, sizeof(data)) == NULL); + EXPECT_TRUE(buffer->GetRange(kDataSize, 1) == NULL); + EXPECT_TRUE(buffer->GetRange(0, kDataSize + 1) == NULL); + EXPECT_TRUE(buffer->GetRange(-1, kDataSize) == NULL); EXPECT_TRUE(buffer->GetRange(-0, -1) == NULL); const int size = 0x20000; DoBufferData(buffer, size / 2, GL_STATIC_DRAW, NULL, GL_NO_ERROR); @@ -350,7 +350,7 @@ TEST_F(BufferManagerTest, UseDeletedBuffer) { const GLuint kClientBufferId = 1; const GLuint kServiceBufferId = 11; - const uint32 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + const GLsizeiptr kDataSize = 10; manager_->CreateBuffer(kClientBufferId, kServiceBufferId); scoped_refptr<Buffer> buffer = manager_->GetBuffer(kClientBufferId); ASSERT_TRUE(buffer.get() != NULL); @@ -358,7 +358,7 @@ // Remove buffer manager_->RemoveBuffer(kClientBufferId); // Use it after removing - DoBufferData(buffer.get(), sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); + DoBufferData(buffer.get(), kDataSize, GL_STATIC_DRAW, NULL, GL_NO_ERROR); // Check that it gets deleted when the last reference is released. EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kServiceBufferId))) .Times(1)
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc index ffb9370..49bba9b 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -218,7 +218,6 @@ GLuint source_id, GLuint dest_id, GLint dest_level, - GLenum dest_internal_format, GLsizei width, GLsizei height, GLuint framebuffer) { @@ -231,14 +230,8 @@ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glCopyTexImage2D(GL_TEXTURE_2D, - dest_level, - dest_internal_format, - 0 /* x */, - 0 /* y */, - width, - height, - 0 /* border */); + glCopyTexSubImage2D(GL_TEXTURE_2D, dest_level, 0 /* xoffset */, + 0 /* yoffset */, 0 /* x */, 0 /* y */, width, height); } decoder->RestoreTextureState(source_id); @@ -332,16 +325,15 @@ bool source_format_contain_superset_of_dest_format = source_internal_format == dest_internal_format || (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB); - // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2, - // so restrict this to GL_TEXTURE_2D. - if (source_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change && + bool source_target_allowed = source_target == GL_TEXTURE_2D || + source_target == GL_TEXTURE_RECTANGLE_ARB; + if (source_target_allowed && !flip_y && !premultiply_alpha_change && source_format_contain_superset_of_dest_format) { DoCopyTexImage2D(decoder, source_target, source_id, dest_id, dest_level, - dest_internal_format, width, height, framebuffer_);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc index a858cf7..fd28f75 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc
@@ -54,8 +54,7 @@ using namespace cmds; TEST_P(GLES2DecoderWithShaderTest, GetVertexAttribPointervSucceeds) { - const float dummy = 0; - const GLuint kOffsetToTestFor = sizeof(dummy) * 4; + const GLuint kOffsetToTestFor = sizeof(float) * 4; const GLuint kIndexToTest = 1; GetVertexAttribPointerv::Result* result = static_cast<GetVertexAttribPointerv::Result*>(shared_memory_address_);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 36afe38..a27bb3d 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -1532,8 +1532,7 @@ void GLES2DecoderTestBase::SetupVertexBuffer() { DoEnableVertexAttribArray(1); DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId); - GLfloat f = 0; - DoBufferData(GL_ARRAY_BUFFER, kNumVertices * 2 * sizeof(f)); + DoBufferData(GL_ARRAY_BUFFER, kNumVertices * 2 * sizeof(GLfloat)); } void GLES2DecoderTestBase::SetupAllNeededVertexBuffers() {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc index 789b48a..78fa020 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -644,11 +644,10 @@ TEST_P(GLES2DecoderTest, ReadPixelsInvalidArgs) { typedef ReadPixels::Result Result; - Result* result = GetSharedMemoryAs<Result*>(); uint32 result_shm_id = kSharedMemoryId; uint32 result_shm_offset = kSharedMemoryOffset; uint32 pixels_shm_id = kSharedMemoryId; - uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result); + uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); EXPECT_CALL(*gl_, ReadPixels(_, _, _, _, _, _, _)).Times(0); ReadPixels cmd; cmd.Init(0, @@ -750,14 +749,13 @@ InitDecoder(init); typedef ReadPixels::Result Result; - Result* result = GetSharedMemoryAs<Result*>(); const GLsizei kWidth = 4; const GLsizei kHeight = 4; uint32 result_shm_id = kSharedMemoryId; uint32 result_shm_offset = kSharedMemoryOffset; uint32 pixels_shm_id = kSharedMemoryId; - uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result); + uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); EXPECT_CALL(*gl_, GetError()) // first error check must pass to get to the test @@ -1637,11 +1635,10 @@ GLsizei width = 2; GLsizei height = 4; typedef ReadPixels::Result Result; - Result* result = GetSharedMemoryAs<Result*>(); uint32 result_shm_id = kSharedMemoryId; uint32 result_shm_offset = kSharedMemoryOffset; uint32 pixels_shm_id = kSharedMemoryId; - uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result); + uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); EXPECT_CALL(*gl_, GetError()) .WillOnce(Return(GL_NO_ERROR)) .WillOnce(Return(GL_OUT_OF_MEMORY)) @@ -1765,11 +1762,10 @@ .Times(1) .RetiresOnSaturation(); typedef ReadPixels::Result Result; - Result* result = GetSharedMemoryAs<Result*>(); uint32 result_shm_id = kSharedMemoryId; uint32 result_shm_offset = kSharedMemoryOffset; uint32 pixels_shm_id = kSharedMemoryId; - uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result); + uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); ReadPixels cmd; cmd.Init(0, 0,
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc index 2c44e1a..a8cbb66 100644 --- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc +++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -76,6 +76,43 @@ EXPECT_TRUE(GL_NO_ERROR == glGetError()); } +TEST_F(GLCopyTextureCHROMIUMTest, ImmutableTexture) { + if (!GLTestHelper::HasExtension("GL_EXT_texture_storage")) { + LOG(INFO) << "GL_EXT_texture_storage not supported. Skipping test..."; + return; + } + + uint8 pixels[1 * 4] = {255u, 0u, 0u, 255u}; + + glBindTexture(GL_TEXTURE_2D, textures_[0]); + glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, 1, 1); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, + pixels); + + glBindTexture(GL_TEXTURE_2D, textures_[1]); + glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, 1, 1); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + textures_[1], 0); + EXPECT_TRUE(glGetError() == GL_NO_ERROR); + + glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, GL_RGBA, + GL_UNSIGNED_BYTE); + EXPECT_TRUE(glGetError() == GL_NO_ERROR); + + // Check the FB is still bound. + GLint value = 0; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value); + GLuint fb_id = value; + EXPECT_EQ(framebuffer_id_, fb_id); + + // Check that FB is complete. + EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), + glCheckFramebufferStatus(GL_FRAMEBUFFER)); + + GLTestHelper::CheckPixels(0, 0, 1, 1, 0, pixels); + EXPECT_TRUE(GL_NO_ERROR == glGetError()); +} + TEST_F(GLCopyTextureCHROMIUMTest, InternalFormat) { GLint src_formats[] = {GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGRA_EXT};
diff --git a/mojo/services/surfaces/surfaces_impl.cc b/mojo/services/surfaces/surfaces_impl.cc index 6d98c9d..10414f9 100644 --- a/mojo/services/surfaces/surfaces_impl.cc +++ b/mojo/services/surfaces/surfaces_impl.cc
@@ -80,7 +80,8 @@ return; } if (!display_) { - display_.reset(new cc::Display(this, manager_, NULL, NULL)); + cc::RendererSettings settings; + display_.reset(new cc::Display(this, manager_, nullptr, nullptr, settings)); client_->SetDisplay(display_.get()); display_->Initialize(make_scoped_ptr(new DirectOutputSurface( new ContextProviderMojo(command_buffer_handle_.Pass()))));
diff --git a/net/BUILD.gn b/net/BUILD.gn index be0ac53..a9d20aa 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -406,8 +406,8 @@ "websockets/websocket_frame_parser.h", "websockets/websocket_handshake_constants.cc", "websockets/websocket_handshake_constants.h", - "websockets/websocket_handshake_handler.cc", - "websockets/websocket_handshake_handler.h", + "websockets/websocket_handshake_challenge.cc", + "websockets/websocket_handshake_challenge.h", "websockets/websocket_handshake_request_info.cc", "websockets/websocket_handshake_request_info.h", "websockets/websocket_handshake_response_info.cc", @@ -609,8 +609,12 @@ source_set("test_support") { testonly = true sources = [ + "base/captured_net_log_entry.cc", + "base/captured_net_log_entry.h", "base/capturing_net_log.cc", "base/capturing_net_log.h", + "base/capturing_net_log_observer.cc", + "base/capturing_net_log_observer.h", "base/load_timing_info_test_util.cc", "base/load_timing_info_test_util.h", "base/mock_file_stream.cc", @@ -1238,8 +1242,7 @@ "websockets/websocket_extension_parser_test.cc", "websockets/websocket_frame_parser_test.cc", "websockets/websocket_frame_test.cc", - "websockets/websocket_handshake_handler_spdy_test.cc", - "websockets/websocket_handshake_handler_test.cc", + "websockets/websocket_handshake_challenge_test.cc", "websockets/websocket_handshake_stream_create_helper_test.cc", "websockets/websocket_inflater_test.cc", "websockets/websocket_stream_test.cc",
diff --git a/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java b/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java index 60f910c..2a6c2f2 100644 --- a/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java +++ b/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java
@@ -123,8 +123,8 @@ signature.update(message); return signature.sign(); } catch (Exception e) { - Log.e(TAG, "Exception while signing message with " + javaKey.getAlgorithm() + - " private key: " + e); + Log.e(TAG, "Exception while signing message with " + javaKey.getAlgorithm() + + " private key: " + e); return null; } } @@ -170,8 +170,8 @@ // This may happen if the PrivateKey was not created by the "AndroidOpenSSL" // provider, which should be the default. That could happen if an OEM decided // to implement a different default provider. Also highly unlikely. - Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" + - javaKey.getClass().getCanonicalName()); + Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" + + javaKey.getClass().getCanonicalName()); return null; } @@ -284,8 +284,8 @@ } // Sanity-check the returned engine. if (!engineClass.isInstance(engine)) { - Log.e(TAG, "Engine is not an OpenSSLEngine instance, its class name is:" + - engine.getClass().getCanonicalName()); + Log.e(TAG, "Engine is not an OpenSSLEngine instance, its class name is:" + + engine.getClass().getCanonicalName()); return null; } return engine;
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java index 1e72da9..9db46e2 100644 --- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java +++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -161,8 +161,8 @@ public int getCurrentConnectionType() { // Track exactly what type of connection we have. - if (!mConnectivityManagerDelegate.activeNetworkExists() || - !mConnectivityManagerDelegate.isConnected()) { + if (!mConnectivityManagerDelegate.activeNetworkExists() + || !mConnectivityManagerDelegate.isConnected()) { return NetworkChangeNotifier.CONNECTION_NONE; }
diff --git a/net/android/java/src/org/chromium/net/X509Util.java b/net/android/java/src/org/chromium/net/X509Util.java index 3f6c70d..08ead31 100644 --- a/net/android/java/src/org/chromium/net/X509Util.java +++ b/net/android/java/src/org/chromium/net/X509Util.java
@@ -372,8 +372,8 @@ // If the subject and public key match, this is a system root. X509Certificate anchorX509 = (X509Certificate) anchor; - if (root.getSubjectX500Principal().equals(anchorX509.getSubjectX500Principal()) && - root.getPublicKey().equals(anchorX509.getPublicKey())) { + if (root.getSubjectX500Principal().equals(anchorX509.getSubjectX500Principal()) + && root.getPublicKey().equals(anchorX509.getPublicKey())) { sSystemTrustAnchorCache.add(key); return true; } @@ -405,10 +405,10 @@ if (ekuOids == null) return true; for (String ekuOid : ekuOids) { - if (ekuOid.equals(OID_TLS_SERVER_AUTH) || - ekuOid.equals(OID_ANY_EKU) || - ekuOid.equals(OID_SERVER_GATED_NETSCAPE) || - ekuOid.equals(OID_SERVER_GATED_MICROSOFT)) { + if (ekuOid.equals(OID_TLS_SERVER_AUTH) + || ekuOid.equals(OID_ANY_EKU) + || ekuOid.equals(OID_SERVER_GATED_NETSCAPE) + || ekuOid.equals(OID_SERVER_GATED_MICROSOFT)) { return true; } } @@ -421,8 +421,8 @@ String host) throws KeyStoreException, NoSuchAlgorithmException { if (certChain == null || certChain.length == 0 || certChain[0] == null) { - throw new IllegalArgumentException("Expected non-null and non-empty certificate " + - "chain passed as |certChain|. |certChain|=" + Arrays.deepToString(certChain)); + throw new IllegalArgumentException("Expected non-null and non-empty certificate " + + "chain passed as |certChain|. |certChain|=" + Arrays.deepToString(certChain)); } @@ -475,8 +475,8 @@ } catch (CertificateException eTestManager) { // Neither of the trust managers confirms the validity of the certificate chain, // log the error message returned by the system trust manager. - Log.i(TAG, "Failed to validate the certificate chain, error: " + - eDefaultManager.getMessage()); + Log.i(TAG, "Failed to validate the certificate chain, error: " + + eDefaultManager.getMessage()); return new AndroidCertVerifyResult( CertVerifyStatusAndroid.NO_TRUSTED_ROOT); }
diff --git a/net/base/captured_net_log_entry.cc b/net/base/captured_net_log_entry.cc new file mode 100644 index 0000000..9c57271 --- /dev/null +++ b/net/base/captured_net_log_entry.cc
@@ -0,0 +1,77 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/base/captured_net_log_entry.h" + +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/values.h" + +namespace net { + +CapturedNetLogEntry::CapturedNetLogEntry( + NetLog::EventType type, + const base::TimeTicks& time, + NetLog::Source source, + NetLog::EventPhase phase, + scoped_ptr<base::DictionaryValue> params) + : type(type), + time(time), + source(source), + phase(phase), + params(params.Pass()) { + // Only entries without a NetLog should have an invalid source. + CHECK(source.IsValid()); +} + +CapturedNetLogEntry::CapturedNetLogEntry(const CapturedNetLogEntry& entry) { + *this = entry; +} + +CapturedNetLogEntry::~CapturedNetLogEntry() {} + +CapturedNetLogEntry& CapturedNetLogEntry::operator=( + const CapturedNetLogEntry& entry) { + type = entry.type; + time = entry.time; + source = entry.source; + phase = entry.phase; + params.reset(entry.params ? entry.params->DeepCopy() : NULL); + return *this; +} + +bool CapturedNetLogEntry::GetStringValue(const std::string& name, + std::string* value) const { + if (!params) + return false; + return params->GetString(name, value); +} + +bool CapturedNetLogEntry::GetIntegerValue(const std::string& name, + int* value) const { + if (!params) + return false; + return params->GetInteger(name, value); +} + +bool CapturedNetLogEntry::GetListValue(const std::string& name, + base::ListValue** value) const { + if (!params) + return false; + return params->GetList(name, value); +} + +bool CapturedNetLogEntry::GetNetErrorCode(int* value) const { + return GetIntegerValue("net_error", value); +} + +std::string CapturedNetLogEntry::GetParamsJson() const { + if (!params) + return std::string(); + std::string json; + base::JSONWriter::Write(params.get(), &json); + return json; +} + +} // namespace net
diff --git a/net/base/captured_net_log_entry.h b/net/base/captured_net_log_entry.h new file mode 100644 index 0000000..97245e3 --- /dev/null +++ b/net/base/captured_net_log_entry.h
@@ -0,0 +1,69 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_BASE_CAPTURED_NET_LOG_ENTRY_H_ +#define NET_BASE_CAPTURED_NET_LOG_ENTRY_H_ + +#include <string> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "net/base/net_log.h" + +namespace base { +class DictionaryValue; +class ListValue; +} + +namespace net { + +// CapturedNetLogEntry is much like NetLog::Entry, except it has its own copy of +// all log data, so a list of entries can be gathered over the course of a test, +// and then inspected at the end. It is intended for testing only, and is part +// of the net_test_support project. +struct CapturedNetLogEntry { + // Ordered set of logged entries. + typedef std::vector<CapturedNetLogEntry> List; + + CapturedNetLogEntry(NetLog::EventType type, + const base::TimeTicks& time, + NetLog::Source source, + NetLog::EventPhase phase, + scoped_ptr<base::DictionaryValue> params); + // Copy constructor needed to store in a std::vector because of the + // scoped_ptr. + CapturedNetLogEntry(const CapturedNetLogEntry& entry); + + ~CapturedNetLogEntry(); + + // Equality operator needed to store in a std::vector because of the + // scoped_ptr. + CapturedNetLogEntry& operator=(const CapturedNetLogEntry& entry); + + // Attempt to retrieve an value of the specified type with the given name + // from |params|. Returns true on success, false on failure. Does not + // modify |value| on failure. + bool GetStringValue(const std::string& name, std::string* value) const; + bool GetIntegerValue(const std::string& name, int* value) const; + bool GetListValue(const std::string& name, base::ListValue** value) const; + + // Same as GetIntegerValue, but returns the error code associated with a + // log entry. + bool GetNetErrorCode(int* value) const; + + // Returns the parameters as a JSON string, or empty string if there are no + // parameters. + std::string GetParamsJson() const; + + NetLog::EventType type; + base::TimeTicks time; + NetLog::Source source; + NetLog::EventPhase phase; + scoped_ptr<base::DictionaryValue> params; +}; + +} // namespace net + +#endif // NET_BASE_CAPTURED_NET_LOG_ENTRY_H_
diff --git a/net/base/capturing_net_log.cc b/net/base/capturing_net_log.cc index 3837fe6..f2e2c04 100644 --- a/net/base/capturing_net_log.cc +++ b/net/base/capturing_net_log.cc
@@ -4,130 +4,8 @@ #include "net/base/capturing_net_log.h" -#include "base/json/json_writer.h" -#include "base/logging.h" -#include "base/values.h" - namespace net { -CapturingNetLog::CapturedEntry::CapturedEntry( - EventType type, - const base::TimeTicks& time, - Source source, - EventPhase phase, - scoped_ptr<base::DictionaryValue> params) - : type(type), - time(time), - source(source), - phase(phase), - params(params.Pass()) { -} - -CapturingNetLog::CapturedEntry::CapturedEntry(const CapturedEntry& entry) { - *this = entry; -} - -CapturingNetLog::CapturedEntry::~CapturedEntry() {} - -CapturingNetLog::CapturedEntry& -CapturingNetLog::CapturedEntry::operator=(const CapturedEntry& entry) { - type = entry.type; - time = entry.time; - source = entry.source; - phase = entry.phase; - params.reset(entry.params ? entry.params->DeepCopy() : NULL); - return *this; -} - -bool CapturingNetLog::CapturedEntry::GetStringValue( - const std::string& name, - std::string* value) const { - if (!params) - return false; - return params->GetString(name, value); -} - -bool CapturingNetLog::CapturedEntry::GetIntegerValue( - const std::string& name, - int* value) const { - if (!params) - return false; - return params->GetInteger(name, value); -} - -bool CapturingNetLog::CapturedEntry::GetListValue( - const std::string& name, - base::ListValue** value) const { - if (!params) - return false; - return params->GetList(name, value); -} - -bool CapturingNetLog::CapturedEntry::GetNetErrorCode(int* value) const { - return GetIntegerValue("net_error", value); -} - -std::string CapturingNetLog::CapturedEntry::GetParamsJson() const { - if (!params) - return std::string(); - std::string json; - base::JSONWriter::Write(params.get(), &json); - return json; -} - -CapturingNetLog::Observer::Observer() {} - -CapturingNetLog::Observer::~Observer() {} - -void CapturingNetLog::Observer::GetEntries( - CapturedEntryList* entry_list) const { - base::AutoLock lock(lock_); - *entry_list = captured_entries_; -} - -void CapturingNetLog::Observer::GetEntriesForSource( - NetLog::Source source, - CapturedEntryList* entry_list) const { - base::AutoLock lock(lock_); - entry_list->clear(); - for (CapturedEntryList::const_iterator entry = captured_entries_.begin(); - entry != captured_entries_.end(); ++entry) { - if (entry->source.id == source.id) - entry_list->push_back(*entry); - } -} - -size_t CapturingNetLog::Observer::GetSize() const { - base::AutoLock lock(lock_); - return captured_entries_.size(); -} - -void CapturingNetLog::Observer::Clear() { - base::AutoLock lock(lock_); - captured_entries_.clear(); -} - -void CapturingNetLog::Observer::OnAddEntry(const net::NetLog::Entry& entry) { - // Only BoundNetLogs without a NetLog should have an invalid source. - CHECK(entry.source().IsValid()); - - // Using Dictionaries instead of Values makes checking values a little - // simpler. - base::DictionaryValue* param_dict = NULL; - base::Value* param_value = entry.ParametersToValue(); - if (param_value && !param_value->GetAsDictionary(¶m_dict)) - delete param_value; - - // Only need to acquire the lock when accessing class variables. - base::AutoLock lock(lock_); - captured_entries_.push_back( - CapturedEntry(entry.type(), - base::TimeTicks::Now(), - entry.source(), - entry.phase(), - scoped_ptr<base::DictionaryValue>(param_dict))); -} - CapturingNetLog::CapturingNetLog() { AddThreadSafeObserver(&capturing_net_log_observer_, LOG_ALL_BUT_BYTES); }
diff --git a/net/base/capturing_net_log.h b/net/base/capturing_net_log.h index 5977533..452c9a0 100644 --- a/net/base/capturing_net_log.h +++ b/net/base/capturing_net_log.h
@@ -8,68 +8,22 @@ #include <string> #include <vector> -#include "base/atomicops.h" #include "base/basictypes.h" #include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/synchronization/lock.h" -#include "base/time/time.h" +#include "net/base/captured_net_log_entry.h" +#include "net/base/capturing_net_log_observer.h" #include "net/base/net_log.h" -namespace base { -class DictionaryValue; -class ListValue; -} - namespace net { -// CapturingNetLog is a NetLog which instantiates Observer that saves messages -// to a bounded buffer. It is intended for testing only, and is part of the -// net_test_support project. This is provided for convinience and compatilbility -// with the old unittests. +// CapturingNetLog is convenience class which combines a NetLog and a +// CapturingNetLogObserver. It is intended for testing only, and is part of the +// net_test_support project. class CapturingNetLog : public NetLog { public: - struct CapturedEntry { - CapturedEntry(EventType type, - const base::TimeTicks& time, - Source source, - EventPhase phase, - scoped_ptr<base::DictionaryValue> params); - // Copy constructor needed to store in a std::vector because of the - // scoped_ptr. - CapturedEntry(const CapturedEntry& entry); - - ~CapturedEntry(); - - // Equality operator needed to store in a std::vector because of the - // scoped_ptr. - CapturedEntry& operator=(const CapturedEntry& entry); - - // Attempt to retrieve an value of the specified type with the given name - // from |params|. Returns true on success, false on failure. Does not - // modify |value| on failure. - bool GetStringValue(const std::string& name, std::string* value) const; - bool GetIntegerValue(const std::string& name, int* value) const; - bool GetListValue(const std::string& name, base::ListValue** value) const; - - // Same as GetIntegerValue, but returns the error code associated with a - // log entry. - bool GetNetErrorCode(int* value) const; - - // Returns the parameters as a JSON string, or empty string if there are no - // parameters. - std::string GetParamsJson() const; - - EventType type; - base::TimeTicks time; - Source source; - EventPhase phase; - scoped_ptr<base::DictionaryValue> params; - }; - - // Ordered set of entries that were logged. - typedef std::vector<CapturedEntry> CapturedEntryList; + // TODO(mmenke): Get rid of these. + typedef CapturedNetLogEntry CapturedEntry; + typedef CapturedNetLogEntry::List CapturedEntryList; CapturingNetLog(); ~CapturingNetLog() override; @@ -83,39 +37,7 @@ void Clear(); private: - // Observer is an implementation of NetLog::ThreadSafeObserver - // that saves messages to a bounded buffer. It is intended for testing only, - // and is part of the net_test_support project. - class Observer : public NetLog::ThreadSafeObserver { - public: - Observer(); - ~Observer() override; - - // Returns the list of all entries in the log. - void GetEntries(CapturedEntryList* entry_list) const; - - // Fills |entry_list| with all entries in the log from the specified Source. - void GetEntriesForSource(Source source, - CapturedEntryList* entry_list) const; - - // Returns number of entries in the log. - size_t GetSize() const; - - void Clear(); - - private: - // ThreadSafeObserver implementation: - void OnAddEntry(const Entry& entry) override; - - // Needs to be "mutable" so can use it in GetEntries(). - mutable base::Lock lock_; - - CapturedEntryList captured_entries_; - - DISALLOW_COPY_AND_ASSIGN(Observer); - }; - - Observer capturing_net_log_observer_; + CapturingNetLogObserver capturing_net_log_observer_; DISALLOW_COPY_AND_ASSIGN(CapturingNetLog); }; @@ -123,7 +45,7 @@ // Helper class that exposes a similar API as BoundNetLog, but uses a // CapturingNetLog rather than the more generic NetLog. // -// CapturingBoundNetLog can easily be converted to a BoundNetLog using the +// A CapturingBoundNetLog can easily be converted to a BoundNetLog using the // bound() method. class CapturingBoundNetLog { public:
diff --git a/net/base/capturing_net_log_observer.cc b/net/base/capturing_net_log_observer.cc new file mode 100644 index 0000000..da99852 --- /dev/null +++ b/net/base/capturing_net_log_observer.cc
@@ -0,0 +1,62 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/base/capturing_net_log_observer.h" + +#include "base/values.h" + +namespace net { + +CapturingNetLogObserver::CapturingNetLogObserver() {} + +CapturingNetLogObserver::~CapturingNetLogObserver() {} + +void CapturingNetLogObserver::GetEntries( + CapturedNetLogEntry::List* entry_list) const { + base::AutoLock lock(lock_); + *entry_list = captured_entries_; +} + +void CapturingNetLogObserver::GetEntriesForSource( + NetLog::Source source, + CapturedNetLogEntry::List* entry_list) const { + base::AutoLock lock(lock_); + entry_list->clear(); + for (CapturedNetLogEntry::List::const_iterator entry = + captured_entries_.begin(); + entry != captured_entries_.end(); ++entry) { + if (entry->source.id == source.id) + entry_list->push_back(*entry); + } +} + +size_t CapturingNetLogObserver::GetSize() const { + base::AutoLock lock(lock_); + return captured_entries_.size(); +} + +void CapturingNetLogObserver::Clear() { + base::AutoLock lock(lock_); + captured_entries_.clear(); +} + +void CapturingNetLogObserver::OnAddEntry(const net::NetLog::Entry& entry) { + // Using Dictionaries instead of Values makes checking values a little + // simpler. + base::DictionaryValue* param_dict = nullptr; + base::Value* param_value = entry.ParametersToValue(); + if (param_value && !param_value->GetAsDictionary(¶m_dict)) + delete param_value; + + // Only need to acquire the lock when accessing class variables. + base::AutoLock lock(lock_); + captured_entries_.push_back( + CapturedNetLogEntry(entry.type(), + base::TimeTicks::Now(), + entry.source(), + entry.phase(), + scoped_ptr<base::DictionaryValue>(param_dict))); +} + +} // namespace net
diff --git a/net/base/capturing_net_log_observer.h b/net/base/capturing_net_log_observer.h new file mode 100644 index 0000000..267352a --- /dev/null +++ b/net/base/capturing_net_log_observer.h
@@ -0,0 +1,58 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_BASE_CAPTURING_NET_LOG_OBSERVER_H_ +#define NET_BASE_CAPTURING_NET_LOG_OBSERVER_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/synchronization/lock.h" +#include "net/base/captured_net_log_entry.h" +#include "net/base/net_log.h" + +namespace base { +class DictionaryValue; +class ListValue; +} + +namespace net { + +// CapturingNetLogObserver is an implementation of NetLog::ThreadSafeObserver +// that saves messages to a bounded buffer. It is intended for testing only, +// and is part of the net_test_support project. +class CapturingNetLogObserver : public NetLog::ThreadSafeObserver { + public: + CapturingNetLogObserver(); + ~CapturingNetLogObserver() override; + + // Returns the list of all entries in the log. + void GetEntries(CapturedNetLogEntry::List* entry_list) const; + + // Fills |entry_list| with all entries in the log from the specified Source. + void GetEntriesForSource(NetLog::Source source, + CapturedNetLogEntry::List* entry_list) const; + + // Returns number of entries in the log. + size_t GetSize() const; + + void Clear(); + + private: + // ThreadSafeObserver implementation: + void OnAddEntry(const NetLog::Entry& entry) override; + + // Needs to be "mutable" so can use it in GetEntries(). + mutable base::Lock lock_; + + CapturedNetLogEntry::List captured_entries_; + + DISALLOW_COPY_AND_ASSIGN(CapturingNetLogObserver); +}; + +} // namespace net + +#endif // NET_BASE_CAPTURING_NET_LOG_OBSERVER_H_
diff --git a/net/base/file_stream_context_win.cc b/net/base/file_stream_context_win.cc index 3b942d3..369dfc1 100644 --- a/net/base/file_stream_context_win.cc +++ b/net/base/file_stream_context_win.cc
@@ -68,14 +68,13 @@ if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len, &bytes_read, &io_context_.overlapped)) { IOResult error = IOResult::FromOSError(GetLastError()); - if (error.os_error == ERROR_IO_PENDING) { - IOCompletionIsPending(callback, buf); - } else if (error.os_error == ERROR_HANDLE_EOF) { + if (error.os_error == ERROR_HANDLE_EOF) return 0; // Report EOF by returning 0 bytes read. - } else { + if (error.os_error == ERROR_IO_PENDING) + IOCompletionIsPending(callback, buf); + else LOG(WARNING) << "ReadFile failed: " << error.os_error; - } - return error.result; + return static_cast<int>(error.result); } IOCompletionIsPending(callback, buf); @@ -89,12 +88,11 @@ if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len, &bytes_written, &io_context_.overlapped)) { IOResult error = IOResult::FromOSError(GetLastError()); - if (error.os_error == ERROR_IO_PENDING) { + if (error.os_error == ERROR_IO_PENDING) IOCompletionIsPending(callback, buf); - } else { + else LOG(WARNING) << "WriteFile failed: " << error.os_error; - } - return error.result; + return static_cast<int>(error.result); } IOCompletionIsPending(callback, buf); @@ -149,7 +147,7 @@ result = 0; } else if (error) { IOResult error_result = IOResult::FromOSError(error); - result = error_result.result; + result = static_cast<int>(error_result.result); } else { result = bytes_read; IncrementOffset(&io_context_.overlapped, bytes_read);
diff --git a/net/base/host_mapping_rules.cc b/net/base/host_mapping_rules.cc index f91f3fd..01b98b7 100644 --- a/net/base/host_mapping_rules.cc +++ b/net/base/host_mapping_rules.cc
@@ -58,7 +58,7 @@ host_port->set_host(rule.replacement_hostname); if (rule.replacement_port != -1) - host_port->set_port(rule.replacement_port); + host_port->set_port(static_cast<uint16>(rule.replacement_port)); return true; }
diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc index 18cf9f5..1570bbb 100644 --- a/net/base/host_port_pair.cc +++ b/net/base/host_port_pair.cc
@@ -21,7 +21,8 @@ // static HostPortPair HostPortPair::FromURL(const GURL& url) { - return HostPortPair(url.HostNoBrackets(), url.EffectiveIntPort()); + return HostPortPair(url.HostNoBrackets(), + static_cast<uint16>(url.EffectiveIntPort())); } // static @@ -41,7 +42,7 @@ return HostPortPair(); HostPortPair host_port_pair; host_port_pair.set_host(key_port[0]); - host_port_pair.set_port(port); + host_port_pair.set_port(static_cast<uint16>(port)); return host_port_pair; }
diff --git a/net/base/ip_endpoint.cc b/net/base/ip_endpoint.cc index a0d378e..65c5d50 100644 --- a/net/base/ip_endpoint.cc +++ b/net/base/ip_endpoint.cc
@@ -25,7 +25,7 @@ IPEndPoint::~IPEndPoint() {} -IPEndPoint::IPEndPoint(const IPAddressNumber& address, int port) +IPEndPoint::IPEndPoint(const IPAddressNumber& address, uint16 port) : address_(address), port_(port) {}
diff --git a/net/base/ip_endpoint.h b/net/base/ip_endpoint.h index 5e5d9c1..c2639b1 100644 --- a/net/base/ip_endpoint.h +++ b/net/base/ip_endpoint.h
@@ -24,11 +24,11 @@ public: IPEndPoint(); ~IPEndPoint(); - IPEndPoint(const IPAddressNumber& address, int port); + IPEndPoint(const IPAddressNumber& address, uint16 port); IPEndPoint(const IPEndPoint& endpoint); const IPAddressNumber& address() const { return address_; } - int port() const { return port_; } + uint16 port() const { return port_; } // Returns AddressFamily of the address. AddressFamily GetFamily() const; @@ -66,7 +66,7 @@ private: IPAddressNumber address_; - int port_; + uint16 port_; }; } // namespace net
diff --git a/net/base/ip_endpoint_unittest.cc b/net/base/ip_endpoint_unittest.cc index 5d70911..17b325c 100644 --- a/net/base/ip_endpoint_unittest.cc +++ b/net/base/ip_endpoint_unittest.cc
@@ -29,7 +29,7 @@ { "::1", "[::1]", true }, { "2001:db8:0::42", "[2001:db8::42]", true }, }; -int test_count = arraysize(tests); +uint16 test_count = static_cast<uint16>(arraysize(tests)); class IPEndPointTest : public PlatformTest { public: @@ -46,7 +46,7 @@ IPEndPoint endpoint; EXPECT_EQ(0, endpoint.port()); - for (int index = 0; index < test_count; ++index) { + for (uint16 index = 0; index < test_count; ++index) { IPEndPoint endpoint(tests[index].ip_address, 80); EXPECT_EQ(80, endpoint.port()); EXPECT_EQ(tests[index].ip_address, endpoint.address()); @@ -54,7 +54,7 @@ } TEST_F(IPEndPointTest, Assignment) { - for (int index = 0; index < test_count; ++index) { + for (uint16 index = 0; index < test_count; ++index) { IPEndPoint src(tests[index].ip_address, index); IPEndPoint dest = src; @@ -64,7 +64,7 @@ } TEST_F(IPEndPointTest, Copy) { - for (int index = 0; index < test_count; ++index) { + for (uint16 index = 0; index < test_count; ++index) { IPEndPoint src(tests[index].ip_address, index); IPEndPoint dest(src); @@ -74,7 +74,7 @@ } TEST_F(IPEndPointTest, ToFromSockAddr) { - for (int index = 0; index < test_count; ++index) { + for (uint16 index = 0; index < test_count; ++index) { IPEndPoint ip_endpoint(tests[index].ip_address, index); // Convert to a sockaddr. @@ -97,7 +97,7 @@ } TEST_F(IPEndPointTest, ToSockAddrBufTooSmall) { - for (int index = 0; index < test_count; ++index) { + for (uint16 index = 0; index < test_count; ++index) { IPEndPoint ip_endpoint(tests[index].ip_address, index); SockaddrStorage storage; @@ -116,7 +116,7 @@ } TEST_F(IPEndPointTest, Equality) { - for (int index = 0; index < test_count; ++index) { + for (uint16 index = 0; index < test_count; ++index) { IPEndPoint src(tests[index].ip_address, index); IPEndPoint dest(src); EXPECT_TRUE(src == dest); @@ -159,8 +159,8 @@ IPEndPoint endpoint; EXPECT_EQ(0, endpoint.port()); - for (int index = 0; index < test_count; ++index) { - int port = 100 + index; + for (uint16 index = 0; index < test_count; ++index) { + uint16 port = 100 + index; IPEndPoint endpoint(tests[index].ip_address, port); const std::string result = endpoint.ToString(); EXPECT_EQ(tests[index].host_normalized + ":" + base::IntToString(port),
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h index 494b762..d6e6187 100644 --- a/net/base/net_log_event_type_list.h +++ b/net/base/net_log_event_type_list.h
@@ -1325,6 +1325,10 @@ EVENT_TYPE(SPDY_STREAM) // A stream is attached to a pushed stream. +// { +// "stream_id": <The stream id>, +// "url": <The url of the pushed resource>, +// } EVENT_TYPE(SPDY_STREAM_ADOPTED_PUSH_STREAM) // A stream is unstalled by flow control.
diff --git a/net/base/net_log_util.cc b/net/base/net_log_util.cc index a15e899..3b437aa 100644 --- a/net/base/net_log_util.cc +++ b/net/base/net_log_util.cc
@@ -4,12 +4,17 @@ #include "net/base/net_log_util.h" +#include <algorithm> #include <string> +#include <vector> +#include "base/bind.h" +#include "base/logging.h" #include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/time/time.h" #include "base/values.h" #include "net/base/address_family.h" #include "net/base/load_states.h" @@ -28,6 +33,7 @@ #include "net/proxy/proxy_service.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_utils.h" +#include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" namespace net { @@ -101,6 +107,25 @@ return http_cache->GetCurrentBackend(); } +// Returns true if |request1| was created before |request2|. +bool RequestCreatedBefore(const net::URLRequest* request1, + const net::URLRequest* request2) { + if (request1->creation_time() < request2->creation_time()) + return true; + if (request1->creation_time() > request2->creation_time()) + return false; + // If requests were created at the same time, sort by ID. Mostly matters for + // testing purposes. + return request1->identifier() < request2->identifier(); +} + +// Returns a Value representing the state of a pre-existing URLRequest when +// net-internals was opened. +base::Value* GetRequestStateAsValue(const net::URLRequest* request, + net::NetLog::LogLevel log_level) { + return request->GetStateAsValue(); +} + } // namespace scoped_ptr<base::DictionaryValue> GetNetConstants() { @@ -298,6 +323,9 @@ NET_EXPORT scoped_ptr<base::DictionaryValue> GetNetInfo( URLRequestContext* context, int info_sources) { + // May only be called on the context's thread. + DCHECK(context->CalledOnValidThread()); + scoped_ptr<base::DictionaryValue> net_info_dict(new base::DictionaryValue()); // TODO(mmenke): The code for most of these sources should probably be moved @@ -489,4 +517,41 @@ return net_info_dict.Pass(); } +NET_EXPORT void CreateNetLogEntriesForActiveObjects( + const std::set<URLRequestContext*>& contexts, + NetLog::ThreadSafeObserver* observer) { + // Not safe to call this when the observer is watching a NetLog. + DCHECK(!observer->net_log()); + + // Put together the list of all requests. + std::vector<const URLRequest*> requests; + for (const auto& context : contexts) { + // May only be called on the context's thread. + DCHECK(context->CalledOnValidThread()); + // Contexts should all be using the same NetLog. + DCHECK_EQ((*contexts.begin())->net_log(), context->net_log()); + for (const auto& request : *context->url_requests()) { + requests.push_back(request); + } + } + + // Sort by creation time. + std::sort(requests.begin(), requests.end(), RequestCreatedBefore); + + // Create fake events. + ScopedVector<NetLog::Entry> entries; + for (const auto& request : requests) { + net::NetLog::ParametersCallback callback = + base::Bind(&GetRequestStateAsValue, base::Unretained(request)); + + net::NetLog::EntryData entry_data(net::NetLog::TYPE_REQUEST_ALIVE, + request->net_log().source(), + net::NetLog::PHASE_BEGIN, + request->creation_time(), + &callback); + NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel()); + observer->OnAddEntry(entry); + } +} + } // namespace net
diff --git a/net/base/net_log_util.h b/net/base/net_log_util.h index d9627da..d6d6857 100644 --- a/net/base/net_log_util.h +++ b/net/base/net_log_util.h
@@ -5,8 +5,11 @@ #ifndef NET_BASE_NET_LOG_UTIL_H_ #define NET_BASE_NET_LOG_UTIL_H_ +#include <set> + #include "base/memory/scoped_ptr.h" #include "net/base/net_export.h" +#include "net/base/net_log.h" namespace base { class DictionaryValue; @@ -28,16 +31,38 @@ // Utility methods for creating NetLog dumps. -// Create a dictionary containing legend for net/ constants. +// Create a dictionary containing a legend for net/ constants. NET_EXPORT scoped_ptr<base::DictionaryValue> GetNetConstants(); // Retrieves a dictionary containing information about the current state of // |context|. |info_sources| is a set of NetInfoSources OR'd together, // indicating just what information is being requested. Each NetInfoSource adds // one top-level entry to the returned dictionary. +// +// May only be called on |context|'s thread. NET_EXPORT scoped_ptr<base::DictionaryValue> GetNetInfo( URLRequestContext* context, int info_sources); +// Takes in a set of contexts and a NetLog::Observer, and passes in +// NetLog::Entries to the observer for certain NetLog::Sources with pending +// events. This allows requests that were ongoing when logging was started to +// have an initial event that has some information. This is particularly useful +// for hung requests. Note that these calls are not protected by the NetLog's +// lock, so this should generally be invoked before the observer starts watching +// the NetLog. +// +// All members of |contexts| must be using the same NetLog, and live on the +// current thread. +// +// Currently only creates events for URLRequests. +// +// The reason for not returning a list of NetLog::Entries is that entries don't +// own most of their data, so it's simplest just to pass them in to the observer +// directly while their data is on the stack. +NET_EXPORT void CreateNetLogEntriesForActiveObjects( + const std::set<URLRequestContext*>& contexts, + NetLog::ThreadSafeObserver* observer); + } // namespace net #endif // NET_BASE_NET_LOG_UTIL_H_
diff --git a/net/base/net_log_util_unittest.cc b/net/base/net_log_util_unittest.cc index e5cc3a3..e052980 100644 --- a/net/base/net_log_util_unittest.cc +++ b/net/base/net_log_util_unittest.cc
@@ -4,12 +4,17 @@ #include "net/base/net_log_util.h" +#include <set> + +#include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/values.h" +#include "net/base/capturing_net_log_observer.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/http/http_cache.h" #include "net/http/http_transaction.h" +#include "net/test/spawned_test_server/spawned_test_server.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -49,6 +54,65 @@ EXPECT_EQ(net_info_without_cache->size(), net_info_with_cache->size()); } +// Make sure CreateNetLogEntriesForActiveObjects works for requests from a +// single URLRequestContext. +TEST(NetLogUtil, CreateNetLogEntriesForActiveObjectsOneContext) { + // Using same context for each iteration makes sure deleted requests don't + // appear in the list, or result in crashes. + TestURLRequestContext context(true); + NetLog net_log; + context.set_net_log(&net_log); + context.Init(); + TestDelegate delegate; + for (size_t num_requests = 0; num_requests < 5; ++num_requests) { + ScopedVector<URLRequest> requests; + for (size_t i = 0; i < num_requests; ++i) { + requests.push_back(context.CreateRequest( + GURL("about:life"), DEFAULT_PRIORITY, &delegate, nullptr).release()); + } + std::set<URLRequestContext*> contexts; + contexts.insert(&context); + CapturingNetLogObserver capturing_observer; + CreateNetLogEntriesForActiveObjects(contexts, &capturing_observer); + CapturedNetLogEntry::List entry_list; + capturing_observer.GetEntries(&entry_list); + ASSERT_EQ(num_requests, entry_list.size()); + + for (size_t i = 0; i < num_requests; ++i) { + EXPECT_EQ(entry_list[i].source.id, requests[i]->net_log().source().id); + } + } +} + +// Make sure CreateNetLogEntriesForActiveObjects works with multiple +// URLRequestContexts. +TEST(NetLogUtil, CreateNetLogEntriesForActiveObjectsMultipleContexts) { + TestDelegate delegate; + for (size_t num_requests = 0; num_requests < 5; ++num_requests) { + ScopedVector<TestURLRequestContext> contexts; + ScopedVector<URLRequest> requests; + NetLog net_log; + std::set<URLRequestContext*> context_set; + for (size_t i = 0; i < num_requests; ++i) { + contexts.push_back(new TestURLRequestContext(true)); + contexts[i]->set_net_log(&net_log); + contexts[i]->Init(); + context_set.insert(contexts[i]); + requests.push_back(contexts[i]->CreateRequest( + GURL("about:hats"), DEFAULT_PRIORITY, &delegate, nullptr).release()); + } + CapturingNetLogObserver capturing_observer; + CreateNetLogEntriesForActiveObjects(context_set, &capturing_observer); + CapturedNetLogEntry::List entry_list; + capturing_observer.GetEntries(&entry_list); + ASSERT_EQ(num_requests, entry_list.size()); + + for (size_t i = 0; i < num_requests; ++i) { + EXPECT_EQ(entry_list[i].source.id, requests[i]->net_log().source().id); + } + } +} + } // namespace } // namespace net
diff --git a/net/base/net_util.cc b/net/base/net_util.cc index 9dcf9df..3b49dff 100644 --- a/net/base/net_util.cc +++ b/net/base/net_util.cc
@@ -306,7 +306,7 @@ return false; } } - return true; + return IsPortValid(port); } bool IsPortAllowedByFtp(int port) { @@ -573,7 +573,7 @@ *address = reinterpret_cast<const uint8*>(&addr->btAddr); *address_len = kBluetoothAddressSize; if (port) - *port = addr->port; + *port = static_cast<uint16>(addr->port); return true; } #endif @@ -1015,8 +1015,7 @@ } NetworkInterface::NetworkInterface() - : type(NetworkChangeNotifier::CONNECTION_UNKNOWN), - network_prefix(0) { + : type(NetworkChangeNotifier::CONNECTION_UNKNOWN), prefix_length(0) { } NetworkInterface::NetworkInterface(const std::string& name, @@ -1024,14 +1023,14 @@ uint32 interface_index, NetworkChangeNotifier::ConnectionType type, const IPAddressNumber& address, - uint32 network_prefix, + uint32 prefix_length, int ip_address_attributes) : name(name), friendly_name(friendly_name), interface_index(interface_index), type(type), address(address), - network_prefix(network_prefix), + prefix_length(prefix_length), ip_address_attributes(ip_address_attributes) { }
diff --git a/net/base/net_util.h b/net/base/net_util.h index 44b913a..9e9dbad 100644 --- a/net/base/net_util.h +++ b/net/base/net_util.h
@@ -468,7 +468,7 @@ uint32 interface_index, NetworkChangeNotifier::ConnectionType type, const IPAddressNumber& address, - uint32 network_prefix, + uint32 prefix_length, int ip_address_attributes); ~NetworkInterface(); @@ -477,7 +477,7 @@ uint32 interface_index; // Always 0 on Android. NetworkChangeNotifier::ConnectionType type; IPAddressNumber address; - uint32 network_prefix; + uint32 prefix_length; int ip_address_attributes; // Combination of |IPAddressAttributes|. }; @@ -487,9 +487,6 @@ enum HostAddressSelectionPolicy { INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES = 0x0, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES = 0x1, - // Include temp address only when interface has both permanent and - // temp addresses. - INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE = 0x2, }; // Returns list of network interfaces except loopback interface. If an
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc index a25903a..cb9ec1f 100644 --- a/net/base/net_util_unittest.cc +++ b/net/base/net_util_unittest.cc
@@ -36,21 +36,22 @@ #include <iphlpapi.h> #include <objbase.h> #include "base/win/windows_version.h" -#include "net/base/net_util_win.h" #endif // OS_WIN #if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_WIN) #include "net/base/address_tracker_linux.h" #endif // !OS_MACOSX && !OS_NACL && !OS_WIN -#if !defined(OS_WIN) +#if defined(OS_WIN) +#include "net/base/net_util_win.h" +#else // OS_WIN #include "net/base/net_util_posix.h" #if defined(OS_MACOSX) #include "net/base/net_util_mac.h" #else // OS_MACOSX #include "net/base/net_util_linux.h" -#endif -#endif // !OS_WIN +#endif // OS_MACOSX +#endif // OS_WIN using base::ASCIIToUTF16; using base::WideToUTF16; @@ -830,8 +831,8 @@ } } EXPECT_FALSE(all_zeroes); - EXPECT_GT(it->network_prefix, 1u); - EXPECT_LE(it->network_prefix, it->address.size() * 8); + EXPECT_GT(it->prefix_length, 1u); + EXPECT_LE(it->prefix_length, it->address.size() * 8); #if defined(OS_WIN) // On Windows |name| is NET_LUID. @@ -877,16 +878,32 @@ } static const char ifname_em1[] = "em1"; +#if defined(OS_WIN) +static const char ifname_vm[] = "VMnet"; +#else static const char ifname_vm[] = "vmnet"; +#endif // OS_WIN static const unsigned char kIPv6LocalAddr[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + +// The following 3 addresses need to be changed together. IPv6Addr is the IPv6 +// address. IPv6Netmask is the mask address with as many leading bits set to 1 +// as the prefix length. IPv6AddrPrefix needs to match IPv6Addr with the same +// number of bits as the prefix length. static const unsigned char kIPv6Addr[] = {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff, 0xfe, 0xe5, 0x00, 0xc3}; +#if defined(OS_WIN) +static const unsigned char kIPv6AddrPrefix[] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; +#endif // OS_WIN +#if defined(OS_MACOSX) static const unsigned char kIPv6Netmask[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +#endif // OS_MACOSX #if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(OS_NACL) @@ -908,8 +925,6 @@ IPAddressNumber ipv6_local_address( kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr)); IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr)); - IPAddressNumber ipv6_netmask(kIPv6Netmask, - kIPv6Netmask + arraysize(kIPv6Netmask)); NetworkInterfaceList results; ::base::hash_set<int> online_links; @@ -960,7 +975,7 @@ GetInterfaceNameVM)); EXPECT_EQ(results.size(), 1ul); EXPECT_EQ(results[0].name, ifname_vm); - EXPECT_EQ(results[0].network_prefix, 1ul); + EXPECT_EQ(results[0].prefix_length, 1ul); EXPECT_EQ(results[0].address, ipv6_address); results.clear(); @@ -1002,7 +1017,7 @@ GetInterfaceName)); EXPECT_EQ(results.size(), 1ul); EXPECT_EQ(results[0].name, ifname_em1); - EXPECT_EQ(results[0].network_prefix, 1ul); + EXPECT_EQ(results[0].prefix_length, 1ul); EXPECT_EQ(results[0].address, ipv6_address); EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY); results.clear(); @@ -1020,7 +1035,7 @@ GetInterfaceName)); EXPECT_EQ(results.size(), 1ul); EXPECT_EQ(results[0].name, ifname_em1); - EXPECT_EQ(results[0].network_prefix, 1ul); + EXPECT_EQ(results[0].prefix_length, 1ul); EXPECT_EQ(results[0].address, ipv6_address); EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED); results.clear(); @@ -1064,7 +1079,7 @@ &ip_attributes_getter)); EXPECT_EQ(results.size(), 1ul); EXPECT_EQ(results[0].name, ifname_vm); - EXPECT_EQ(results[0].network_prefix, 1ul); + EXPECT_EQ(results[0].prefix_length, 1ul); EXPECT_EQ(results[0].address, ipv6_address); results.clear(); @@ -1098,7 +1113,7 @@ &ip_attributes_getter)); EXPECT_EQ(results.size(), 1ul); EXPECT_EQ(results[0].name, ifname_em1); - EXPECT_EQ(results[0].network_prefix, 1ul); + EXPECT_EQ(results[0].prefix_length, 1ul); EXPECT_EQ(results[0].address, ipv6_address); EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY); results.clear(); @@ -1113,12 +1128,181 @@ &ip_attributes_getter)); EXPECT_EQ(results.size(), 1ul); EXPECT_EQ(results[0].name, ifname_em1); - EXPECT_EQ(results[0].network_prefix, 1ul); + EXPECT_EQ(results[0].prefix_length, 1ul); EXPECT_EQ(results[0].address, ipv6_address); EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED); results.clear(); #endif // !OS_IOS } +#elif defined(OS_WIN) // !OS_MACOSX && !OS_WIN && !OS_NACL + +// Helper function to create a valid IP_ADAPTER_ADDRESSES with reasonable +// default value. The output is the |adapter_address|. All the rests are input +// to fill the |adapter_address|. |sock_addrs| are temporary storage used by +// |adapter_address| once the function is returned. +bool FillAdapterAddress(IP_ADAPTER_ADDRESSES* adapter_address, + const char* ifname, + const IPAddressNumber& ip_address, + const IPAddressNumber& ip_netmask, + sockaddr_storage sock_addrs[2]) { + adapter_address->AdapterName = const_cast<char*>(ifname); + adapter_address->FriendlyName = const_cast<PWCHAR>(L"interface"); + adapter_address->IfType = IF_TYPE_ETHERNET_CSMACD; + adapter_address->OperStatus = IfOperStatusUp; + adapter_address->FirstUnicastAddress->DadState = IpDadStatePreferred; + adapter_address->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; + adapter_address->FirstUnicastAddress->SuffixOrigin = IpSuffixOriginOther; + adapter_address->FirstUnicastAddress->PreferredLifetime = 100; + adapter_address->FirstUnicastAddress->ValidLifetime = 1000; + + socklen_t sock_len = sizeof(sockaddr_storage); + + // Convert to sockaddr for next check. + if (!IPEndPoint(ip_address, 0) + .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[0]), + &sock_len)) { + return false; + } + adapter_address->FirstUnicastAddress->Address.lpSockaddr = + reinterpret_cast<sockaddr*>(&sock_addrs[0]); + adapter_address->FirstUnicastAddress->Address.iSockaddrLength = sock_len; + adapter_address->FirstUnicastAddress->OnLinkPrefixLength = 1; + + sock_len = sizeof(sockaddr_storage); + if (!IPEndPoint(ip_netmask, 0) + .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[1]), + &sock_len)) { + return false; + } + adapter_address->FirstPrefix->Address.lpSockaddr = + reinterpret_cast<sockaddr*>(&sock_addrs[1]); + adapter_address->FirstPrefix->Address.iSockaddrLength = sock_len; + adapter_address->FirstPrefix->PrefixLength = 1; + + DCHECK_EQ(sock_addrs[0].ss_family, sock_addrs[1].ss_family); + if (sock_addrs[0].ss_family == AF_INET6) { + adapter_address->Ipv6IfIndex = 0; + } else { + DCHECK_EQ(sock_addrs[0].ss_family, AF_INET); + adapter_address->IfIndex = 0; + } + + return true; +} + +TEST(NetUtilTest, GetNetworkListTrimming) { + IPAddressNumber ipv6_local_address( + kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr)); + IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr)); + IPAddressNumber ipv6_prefix(kIPv6AddrPrefix, + kIPv6AddrPrefix + arraysize(kIPv6AddrPrefix)); + + NetworkInterfaceList results; + sockaddr_storage addresses[2]; + IP_ADAPTER_ADDRESSES adapter_address = {0}; + IP_ADAPTER_UNICAST_ADDRESS address = {0}; + IP_ADAPTER_PREFIX adapter_prefix = {0}; + adapter_address.FirstUnicastAddress = &address; + adapter_address.FirstPrefix = &adapter_prefix; + + // Address of offline links should be ignored. + ASSERT_TRUE(FillAdapterAddress( + &adapter_address /* adapter_address */, ifname_em1 /* ifname */, + ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */, + addresses /* sock_addrs */)); + adapter_address.OperStatus = IfOperStatusDown; + + EXPECT_TRUE(net::internal::GetNetworkListImpl( + &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address)); + + EXPECT_EQ(results.size(), 0ul); + + // Address on loopback interface should be trimmed out. + ASSERT_TRUE(FillAdapterAddress( + &adapter_address /* adapter_address */, ifname_em1 /* ifname */, + ipv6_local_address /* ip_address */, ipv6_prefix /* ip_netmask */, + addresses /* sock_addrs */)); + adapter_address.IfType = IF_TYPE_SOFTWARE_LOOPBACK; + + EXPECT_TRUE(net::internal::GetNetworkListImpl( + &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address)); + EXPECT_EQ(results.size(), 0ul); + + // vmware address should return by default. + ASSERT_TRUE(FillAdapterAddress( + &adapter_address /* adapter_address */, ifname_vm /* ifname */, + ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */, + addresses /* sock_addrs */)); + EXPECT_TRUE(net::internal::GetNetworkListImpl( + &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address)); + EXPECT_EQ(results.size(), 1ul); + EXPECT_EQ(results[0].name, ifname_vm); + EXPECT_EQ(results[0].prefix_length, 1ul); + EXPECT_EQ(results[0].address, ipv6_address); + EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_NONE); + results.clear(); + + // vmware address should be trimmed out if policy specified so. + ASSERT_TRUE(FillAdapterAddress( + &adapter_address /* adapter_address */, ifname_vm /* ifname */, + ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */, + addresses /* sock_addrs */)); + EXPECT_TRUE(net::internal::GetNetworkListImpl( + &results, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address)); + EXPECT_EQ(results.size(), 0ul); + results.clear(); + + // Addresses with incompleted DAD should be ignored. + ASSERT_TRUE(FillAdapterAddress( + &adapter_address /* adapter_address */, ifname_em1 /* ifname */, + ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */, + addresses /* sock_addrs */)); + adapter_address.FirstUnicastAddress->DadState = IpDadStateTentative; + + EXPECT_TRUE(net::internal::GetNetworkListImpl( + &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address)); + EXPECT_EQ(results.size(), 0ul); + results.clear(); + + // Addresses with allowed attribute IpSuffixOriginRandom should be returned + // and attributes should be translated correctly to + // IP_ADDRESS_ATTRIBUTE_TEMPORARY. + ASSERT_TRUE(FillAdapterAddress( + &adapter_address /* adapter_address */, ifname_em1 /* ifname */, + ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */, + addresses /* sock_addrs */)); + adapter_address.FirstUnicastAddress->PrefixOrigin = + IpPrefixOriginRouterAdvertisement; + adapter_address.FirstUnicastAddress->SuffixOrigin = IpSuffixOriginRandom; + + EXPECT_TRUE(net::internal::GetNetworkListImpl( + &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address)); + EXPECT_EQ(results.size(), 1ul); + EXPECT_EQ(results[0].name, ifname_em1); + EXPECT_EQ(results[0].prefix_length, 1ul); + EXPECT_EQ(results[0].address, ipv6_address); + EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY); + results.clear(); + + // Addresses with preferred lifetime 0 should be returned and + // attributes should be translated correctly to + // IP_ADDRESS_ATTRIBUTE_DEPRECATED. + ASSERT_TRUE(FillAdapterAddress( + &adapter_address /* adapter_address */, ifname_em1 /* ifname */, + ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */, + addresses /* sock_addrs */)); + adapter_address.FirstUnicastAddress->PreferredLifetime = 0; + adapter_address.FriendlyName = const_cast<PWCHAR>(L"FriendlyInterfaceName"); + EXPECT_TRUE(net::internal::GetNetworkListImpl( + &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address)); + EXPECT_EQ(results.size(), 1ul); + EXPECT_EQ(results[0].friendly_name, "FriendlyInterfaceName"); + EXPECT_EQ(results[0].name, ifname_em1); + EXPECT_EQ(results[0].prefix_length, 1ul); + EXPECT_EQ(results[0].address, ipv6_address); + EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED); + results.clear(); +} #endif // !OS_MACOSX && !OS_WIN && !OS_NACL
diff --git a/net/base/net_util_win.cc b/net/base/net_util_win.cc index 7d146b9..ec40233 100644 --- a/net/base/net_util_win.cc +++ b/net/base/net_util_win.cc
@@ -85,35 +85,11 @@ free_memory_func && close_handle_func; } -} // namespace internal - -bool GetNetworkList(NetworkInterfaceList* networks, int policy) { - // GetAdaptersAddresses() may require IO operations. - base::ThreadRestrictions::AssertIOAllowed(); - bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA; - ULONG len = 0; - ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0; - // First get number of networks. - ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len); - if (result != ERROR_BUFFER_OVERFLOW) { - // There are 0 networks. - return true; - } - scoped_ptr<char[]> buf(new char[len]); - IP_ADAPTER_ADDRESSES *adapters = - reinterpret_cast<IP_ADAPTER_ADDRESSES *>(buf.get()); - result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len); - if (result != NO_ERROR) { - LOG(ERROR) << "GetAdaptersAddresses failed: " << result; - return false; - } - - // These two variables are used below when this method is asked to pick a - // IPv6 address which has the shortest lifetime. - ULONG ipv6_valid_lifetime = 0; - scoped_ptr<NetworkInterface> ipv6_address; - - for (IP_ADAPTER_ADDRESSES *adapter = adapters; adapter != NULL; +bool GetNetworkListImpl(NetworkInterfaceList* networks, + int policy, + bool is_xp, + const IP_ADAPTER_ADDRESSES* adapters) { + for (const IP_ADAPTER_ADDRESSES* adapter = adapters; adapter != NULL; adapter = adapter->Next) { // Ignore the loopback device. if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) { @@ -128,7 +104,7 @@ // VMware Virtual Ethernet Adapter for VMnet1 // but don't ignore any GUEST side adapters with a description like: // VMware Accelerated AMD PCNet Adapter #2 - if (policy == EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES && + if ((policy & EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES) && strstr(adapter->AdapterName, "VMnet") != NULL) { continue; } @@ -141,7 +117,7 @@ if (endpoint.FromSockAddr(address->Address.lpSockaddr, address->Address.iSockaddrLength)) { // XP has no OnLinkPrefixLength field. - size_t net_prefix = is_xp ? 0 : address->OnLinkPrefixLength; + size_t prefix_length = is_xp ? 0 : address->OnLinkPrefixLength; if (is_xp) { // Prior to Windows Vista the FirstPrefix pointed to the list with // single prefix for each IP address assigned to the adapter. @@ -157,52 +133,72 @@ IPNumberMatchesPrefix(endpoint.address(), network_endpoint.address(), prefix->PrefixLength)) { - net_prefix = std::max<size_t>(net_prefix, prefix->PrefixLength); + prefix_length = + std::max<size_t>(prefix_length, prefix->PrefixLength); } } } + + // If the duplicate address detection (DAD) state is not changed to + // Preferred, skip this address. + if (address->DadState != IpDadStatePreferred) { + continue; + } + uint32 index = (family == AF_INET) ? adapter->IfIndex : adapter->Ipv6IfIndex; - // Pick one IPv6 address with least valid lifetime. - // The reason we are checking |ValidLifeftime| as there is no other - // way identifying the interface type. Usually (and most likely) temp - // IPv6 will have a shorter ValidLifetime value then the permanent - // interface. - if (family == AF_INET6 && - (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE)) { - if (ipv6_valid_lifetime == 0 || - ipv6_valid_lifetime > address->ValidLifetime) { - ipv6_valid_lifetime = address->ValidLifetime; - ipv6_address.reset(new NetworkInterface( - adapter->AdapterName, - base::SysWideToNativeMB(adapter->FriendlyName), - index, - GetNetworkInterfaceType(adapter->IfType), - endpoint.address(), - net_prefix, - IP_ADDRESS_ATTRIBUTE_NONE)); - continue; + + // From http://technet.microsoft.com/en-us/ff568768(v=vs.60).aspx, the + // way to identify a temporary IPv6 Address is to check if + // PrefixOrigin is equal to IpPrefixOriginRouterAdvertisement and + // SuffixOrigin equal to IpSuffixOriginRandom. + int ip_address_attributes = IP_ADDRESS_ATTRIBUTE_NONE; + if (family == AF_INET6) { + if (address->PrefixOrigin == IpPrefixOriginRouterAdvertisement && + address->SuffixOrigin == IpSuffixOriginRandom) { + ip_address_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY; + } + if (address->PreferredLifetime == 0) { + ip_address_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED; } } - networks->push_back( - NetworkInterface(adapter->AdapterName, - base::SysWideToNativeMB(adapter->FriendlyName), - index, - GetNetworkInterfaceType(adapter->IfType), - endpoint.address(), - net_prefix, - IP_ADDRESS_ATTRIBUTE_NONE)); + networks->push_back(NetworkInterface( + adapter->AdapterName, + base::SysWideToNativeMB(adapter->FriendlyName), index, + GetNetworkInterfaceType(adapter->IfType), endpoint.address(), + prefix_length, ip_address_attributes)); } } } } - - if (ipv6_address.get()) { - networks->push_back(*(ipv6_address.get())); - } return true; } +} // namespace internal + +bool GetNetworkList(NetworkInterfaceList* networks, int policy) { + bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA; + ULONG len = 0; + ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0; + // GetAdaptersAddresses() may require IO operations. + base::ThreadRestrictions::AssertIOAllowed(); + ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len); + if (result != ERROR_BUFFER_OVERFLOW) { + // There are 0 networks. + return true; + } + scoped_ptr<char[]> buf(new char[len]); + IP_ADAPTER_ADDRESSES* adapters = + reinterpret_cast<IP_ADAPTER_ADDRESSES*>(buf.get()); + result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len); + if (result != NO_ERROR) { + LOG(ERROR) << "GetAdaptersAddresses failed: " << result; + return false; + } + + return internal::GetNetworkListImpl(networks, policy, is_xp, adapters); +} + WifiPHYLayerProtocol GetWifiPHYLayerProtocol() { const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance(); if (!wlanapi.initialized)
diff --git a/net/base/net_util_win.h b/net/base/net_util_win.h index afa888b..b0c2dd6 100644 --- a/net/base/net_util_win.h +++ b/net/base/net_util_win.h
@@ -8,10 +8,12 @@ // This file is only used to expose some of the internals // of net_util_win.cc to tests. +#include <iphlpapi.h> #include <wlanapi.h> #include "base/win/scoped_handle.h" #include "net/base/net_export.h" +#include "net/base/net_util.h" namespace net { namespace internal { @@ -78,6 +80,12 @@ } }; +NET_EXPORT bool GetNetworkListImpl( + NetworkInterfaceList* networks, + int policy, + bool is_xp, + const IP_ADAPTER_ADDRESSES* ip_adapter_addresses); + } // namespace internal } // namespace net
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc index 5b69cfb..d4aa19e 100644 --- a/net/base/network_delegate.cc +++ b/net/base/network_delegate.cc
@@ -339,12 +339,6 @@ return false; } -int NetworkDelegate::OnBeforeSocketStreamConnect( - SocketStream* socket, - const CompletionCallback& callback) { - return OK; -} - bool NetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url,
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h index 03dee0b..a169fc6 100644 --- a/net/base/network_delegate.h +++ b/net/base/network_delegate.h
@@ -38,7 +38,6 @@ class ProxyInfo; class ProxyServer; class ProxyService; -class SocketStream; class URLRequest; class NET_EXPORT NetworkDelegate : public base::NonThreadSafe { @@ -268,11 +267,6 @@ const GURL& url, const GURL& first_party_for_cookies) const; - // Called before a SocketStream tries to connect. - // See OnBeforeURLRequest for return value description. Returns OK by default. - virtual int OnBeforeSocketStreamConnect( - SocketStream* socket, const CompletionCallback& callback); - // Called when the |referrer_url| for requesting |target_url| during handling // of the |request| is does not comply with the referrer policy (e.g. a // secure referrer for an insecure initial target).
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc index af5e6ee..1aa9627 100644 --- a/net/base/sdch_manager.cc +++ b/net/base/sdch_manager.cc
@@ -9,6 +9,7 @@ #include "base/metrics/histogram.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "base/time/default_clock.h" #include "base/values.h" #include "crypto/sha2.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" @@ -38,9 +39,6 @@ namespace net { -//------------------------------------------------------------------------------ -// static - // Adjust SDCH limits downwards for mobile. #if defined(OS_ANDROID) || defined(OS_IOS) // static @@ -58,7 +56,6 @@ // static bool SdchManager::g_secure_scheme_supported_ = true; -//------------------------------------------------------------------------------ SdchManager::Dictionary::Dictionary(const std::string& dictionary_text, size_t offset, const std::string& client_hash, @@ -73,45 +70,22 @@ domain_(domain), path_(path), expiration_(expiration), - ports_(ports) { + ports_(ports), + clock_(new base::DefaultClock) { } -SdchManager::Dictionary::~Dictionary() { -} +SdchManager::Dictionary::Dictionary(const SdchManager::Dictionary& rhs) + : text_(rhs.text_), + client_hash_(rhs.client_hash_), + url_(rhs.url_), + domain_(rhs.domain_), + path_(rhs.path_), + expiration_(rhs.expiration_), + ports_(rhs.ports_), + clock_(new base::DefaultClock) {} -SdchProblemCode SdchManager::Dictionary::CanAdvertise( - const GURL& target_url) const { - /* The specific rules of when a dictionary should be advertised in an - Avail-Dictionary header are modeled after the rules for cookie scoping. The - terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A - dictionary may be advertised in the Avail-Dictionaries header exactly when - all of the following are true: - 1. The server's effective host name domain-matches the Domain attribute of - the dictionary. - 2. If the dictionary has a Port attribute, the request port is one of the - ports listed in the Port attribute. - 3. The request URI path-matches the path header of the dictionary. - 4. The request is not an HTTPS request. - We can override (ignore) item (4) only when we have explicitly enabled - HTTPS support AND the dictionary acquisition scheme matches the target - url scheme. - */ - if (!DomainMatch(target_url, domain_)) - return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN; - if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort())) - return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST; - if (path_.size() && !PathMatch(target_url.path(), path_)) - return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH; - if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure()) - return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; - if (target_url.SchemeIsSecure() != url_.SchemeIsSecure()) - return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; - if (base::Time::Now() > expiration_) - return SDCH_DICTIONARY_FOUND_EXPIRED; - return SDCH_OK; -} +SdchManager::Dictionary::~Dictionary() {} -//------------------------------------------------------------------------------ // Security functions restricting loads and use of dictionaries. // static @@ -168,7 +142,7 @@ } SdchProblemCode SdchManager::Dictionary::CanUse( - const GURL& referring_url) const { + const GURL& target_url) const { /* 1. The request URL's host name domain-matches the Domain attribute of the dictionary. @@ -180,24 +154,24 @@ HTTPS support AND the dictionary acquisition scheme matches the target url scheme. */ - if (!DomainMatch(referring_url, domain_)) + if (!DomainMatch(target_url, domain_)) return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN; - if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort())) + if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort())) return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST; - if (path_.size() && !PathMatch(referring_url.path(), path_)) + if (path_.size() && !PathMatch(target_url.path(), path_)) return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH; - if (!SdchManager::secure_scheme_supported() && referring_url.SchemeIsSecure()) + if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure()) return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; - if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) + if (target_url.SchemeIsSecure() != url_.SchemeIsSecure()) return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; // TODO(jar): Remove overly restrictive failsafe test (added per security // review) when we have a need to be more general. - if (!referring_url.SchemeIsHTTPOrHTTPS()) + if (!target_url.SchemeIsHTTPOrHTTPS()) return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA; return SDCH_OK; @@ -228,7 +202,54 @@ return gurl.DomainIs(restriction.data(), restriction.size()); } -//------------------------------------------------------------------------------ +bool SdchManager::Dictionary::Expired() const { + return clock_->Now() > expiration_; +} + +void SdchManager::Dictionary::SetClockForTesting( + scoped_ptr<base::Clock> clock) { + clock_ = clock.Pass(); +} + +SdchManager::DictionarySet::DictionarySet() {} + +SdchManager::DictionarySet::~DictionarySet() {} + +std::string SdchManager::DictionarySet::GetDictionaryClientHashList() const { + std::string result; + bool first = true; + for (const auto& entry: dictionaries_) { + if (!first) + result.append(","); + + result.append(entry.second->data.client_hash()); + first = false; + } + return result; +} + +const SdchManager::Dictionary* SdchManager::DictionarySet::GetDictionary( + const std::string& hash) const { + auto it = dictionaries_.find(hash); + if (it == dictionaries_.end()) + return NULL; + + return &it->second->data; +} + +bool SdchManager::DictionarySet::Empty() const { + return dictionaries_.empty(); +} + +void SdchManager::DictionarySet::AddDictionary( + const std::string& server_hash, + const scoped_refptr<base::RefCountedData<SdchManager::Dictionary>>& + dictionary) { + DCHECK(dictionaries_.end() == dictionaries_.find(server_hash)); + + dictionaries_[server_hash] = dictionary; +} + SdchManager::SdchManager() { DCHECK(thread_checker_.CalledOnValidThread()); } @@ -236,7 +257,7 @@ SdchManager::~SdchManager() { DCHECK(thread_checker_.CalledOnValidThread()); while (!dictionaries_.empty()) { - DictionaryMap::iterator it = dictionaries_.begin(); + auto it = dictionaries_.begin(); dictionaries_.erase(it->first); } } @@ -246,7 +267,7 @@ allow_latency_experiment_.clear(); // Note that this may result in not having dictionaries we've advertised - // for incoming responses. The window is relatively small (as ClearData() + // for incoming responses. The window is relatively small (as ClearData() // is not expected to be called frequently), so we rely on meta-refresh // to handle this case. dictionaries_.clear(); @@ -386,7 +407,7 @@ 3 The parent domain of the referrer URL host name is not a top level domain */ - // Item (1) above implies item (2). Spec should be updated. + // Item (1) above implies item (2). Spec should be updated. // I take "host name match" to be "is identical to" if (referring_url.host() != dictionary_url.host() || referring_url.scheme() != dictionary_url.scheme()) @@ -403,51 +424,49 @@ return SDCH_OK; } -SdchProblemCode SdchManager::GetVcdiffDictionary( - const std::string& server_hash, - const GURL& referring_url, - scoped_refptr<Dictionary>* dictionary) { - DCHECK(thread_checker_.CalledOnValidThread()); - *dictionary = NULL; - DictionaryMap::iterator it = dictionaries_.find(server_hash); - if (it == dictionaries_.end()) - return SDCH_DICTIONARY_HASH_NOT_FOUND; +scoped_ptr<SdchManager::DictionarySet> +SdchManager::GetDictionarySet(const GURL& target_url) { + if (IsInSupportedDomain(target_url) != SDCH_OK) + return NULL; - scoped_refptr<Dictionary> matching_dictionary = it->second; - - SdchProblemCode rv = IsInSupportedDomain(referring_url); - if (rv != SDCH_OK) - return rv; - - rv = matching_dictionary->CanUse(referring_url); - if (rv == SDCH_OK) - *dictionary = matching_dictionary; - return rv; -} - -// TODO(jar): If we have evictions from the dictionaries_, then we need to -// change this interface to return a list of reference counted Dictionary -// instances that can be used if/when a server specifies one. -void SdchManager::GetAvailDictionaryList(const GURL& target_url, - std::string* list) { - DCHECK(thread_checker_.CalledOnValidThread()); int count = 0; - for (DictionaryMap::iterator it = dictionaries_.begin(); - it != dictionaries_.end(); ++it) { - SdchProblemCode rv = IsInSupportedDomain(target_url); - if (rv != SDCH_OK) + scoped_ptr<SdchManager::DictionarySet> result(new DictionarySet); + for (const auto& entry: dictionaries_) { + if (entry.second->data.CanUse(target_url) != SDCH_OK) continue; - - if (it->second->CanAdvertise(target_url) != SDCH_OK) + if (entry.second->data.Expired()) continue; ++count; - if (!list->empty()) - list->append(","); - list->append(it->second->client_hash()); + result->AddDictionary(entry.first, entry.second); } - // Watch to see if we have corrupt or numerous dictionaries. - if (count > 0) - UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); + + if (count == 0) + return NULL; + + UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); + + return result.Pass(); +} + +scoped_ptr<SdchManager::DictionarySet> +SdchManager::GetDictionarySetByHash( + const GURL& target_url, + const std::string& server_hash, + SdchProblemCode* problem_code) { + scoped_ptr<SdchManager::DictionarySet> result; + + *problem_code = SDCH_DICTIONARY_HASH_NOT_FOUND; + const auto& it = dictionaries_.find(server_hash); + if (it == dictionaries_.end()) + return result; + + *problem_code = it->second->data.CanUse(target_url); + if (*problem_code != SDCH_OK) + return result; + + result.reset(new DictionarySet); + result->AddDictionary(it->first, it->second); + return result; } // static @@ -465,7 +484,6 @@ DCHECK_EQ(client_hash->length(), 8u); } -//------------------------------------------------------------------------------ // Methods for supporting latency experiments. bool SdchManager::AllowLatencyExperiment(const GURL& url) const { @@ -575,8 +593,8 @@ return rv; // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of - // useless dictionaries. We should probably have a cache eviction plan, - // instead of just blocking additions. For now, with the spec in flux, it + // useless dictionaries. We should probably have a cache eviction plan, + // instead of just blocking additions. For now, with the spec in flux, it // is probably not worth doing eviction handling. if (kMaxDictionarySize < dictionary_text.size()) return SDCH_DICTIONARY_IS_TOO_LARGE; @@ -587,15 +605,22 @@ UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); DVLOG(1) << "Loaded dictionary with client hash " << client_hash << " and server hash " << server_hash; - Dictionary* dictionary = - new Dictionary(dictionary_text, header_end + 2, client_hash, - dictionary_url_normalized, domain, - path, expiration, ports); - dictionaries_[server_hash] = dictionary; + Dictionary dictionary(dictionary_text, header_end + 2, client_hash, + dictionary_url_normalized, domain, path, expiration, + ports); + dictionaries_[server_hash] = + new base::RefCountedData<Dictionary>(dictionary); + return SDCH_OK; } // static +scoped_ptr<SdchManager::DictionarySet> +SdchManager::CreateEmptyDictionarySetForTesting() { + return scoped_ptr<DictionarySet>(new DictionarySet).Pass(); +} + +// static void SdchManager::UrlSafeBase64Encode(const std::string& input, std::string* output) { // Since this is only done during a dictionary load, and hashes are only 8 @@ -612,20 +637,20 @@ value->SetBoolean("secure_scheme_support", secure_scheme_supported()); base::ListValue* entry_list = new base::ListValue(); - for (DictionaryMap::const_iterator it = dictionaries_.begin(); - it != dictionaries_.end(); ++it) { + for (const auto& entry: dictionaries_) { base::DictionaryValue* entry_dict = new base::DictionaryValue(); - entry_dict->SetString("url", it->second->url().spec()); - entry_dict->SetString("client_hash", it->second->client_hash()); - entry_dict->SetString("domain", it->second->domain()); - entry_dict->SetString("path", it->second->path()); + entry_dict->SetString("url", entry.second->data.url().spec()); + entry_dict->SetString("client_hash", entry.second->data.client_hash()); + entry_dict->SetString("domain", entry.second->data.domain()); + entry_dict->SetString("path", entry.second->data.path()); base::ListValue* port_list = new base::ListValue(); - for (std::set<int>::const_iterator port_it = it->second->ports().begin(); - port_it != it->second->ports().end(); ++port_it) { + for (std::set<int>::const_iterator port_it = + entry.second->data.ports().begin(); + port_it != entry.second->data.ports().end(); ++port_it) { port_list->AppendInteger(*port_it); } entry_dict->Set("ports", port_list); - entry_dict->SetString("server_hash", it->first); + entry_dict->SetString("server_hash", entry.first); entry_list->Append(entry_dict); } value->Set("dictionaries", entry_list);
diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h index 016978a..0948b4c 100644 --- a/net/base/sdch_manager.h +++ b/net/base/sdch_manager.h
@@ -2,12 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// This file contains the SdchManager class and two nested classes +// (Dictionary, DictionarySet). SdchManager::Dictionary contains all +// of the information about an SDCH dictionary. The manager is +// responsible for storing those dictionaries, and provides access to +// them through DictionarySet objects. A DictionarySet is an object +// whose lifetime is under the control of the consumer. It is a +// reference to a set of dictionaries, and guarantees that none of +// those dictionaries will be destroyed while the DictionarySet +// reference is alive. + #ifndef NET_BASE_SDCH_MANAGER_H_ #define NET_BASE_SDCH_MANAGER_H_ #include <map> #include <set> #include <string> +#include <vector> #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" @@ -20,6 +31,7 @@ #include "url/gurl.h" namespace base { +class Clock; class Value; } @@ -38,25 +50,22 @@ // These dictionaries are acquired over the net, and include a header // (containing metadata) as well as a VCDIFF dictionary (for use by a VCDIFF // module) to decompress data. +// +// A dictionary held by the manager may nonetheless outlive the manager if +// a DictionarySet object refers to it; see below. class NET_EXPORT SdchManager { public: + class Dictionary; + typedef std::map<std::string, scoped_refptr<base::RefCountedData<Dictionary>>> + DictionaryMap; + // Use the following static limits to block DOS attacks until we implement // a cached dictionary evicition strategy. static const size_t kMaxDictionarySize; static const size_t kMaxDictionaryCount; - // There is one instance of |Dictionary| for each memory-cached SDCH - // dictionary. - class NET_EXPORT_PRIVATE Dictionary : public base::RefCounted<Dictionary> { + class NET_EXPORT_PRIVATE Dictionary { public: - // Sdch filters can get our text to use in decoding compressed data. - const std::string& text() const { return text_; } - - private: - friend class base::RefCounted<Dictionary>; - friend class SdchManager; // Only manager can construct an instance. - FRIEND_TEST_ALL_PREFIXES(SdchManagerTest, PathMatch); - // Construct a vc-diff usable dictionary from the dictionary_text starting // at the given offset. The supplied client_hash should be used to // advertise the dictionary's availability relative to the suppplied URL. @@ -68,7 +77,11 @@ const std::string& path, const base::Time& expiration, const std::set<int>& ports); - virtual ~Dictionary(); + + ~Dictionary(); + + // Sdch filters can get our text to use in decoding compressed data. + const std::string& text() const { return text_; } const GURL& url() const { return url_; } const std::string& client_hash() const { return client_hash_; } @@ -77,10 +90,6 @@ const base::Time& expiration() const { return expiration_; } const std::set<int>& ports() const { return ports_; } - // Security method to check if we can advertise this dictionary for use - // if the |target_url| returns SDCH compressed data. - SdchProblemCode CanAdvertise(const GURL& target_url) const; - // Security methods to check if we can establish a new dictionary with the // given data, that arrived in response to get of dictionary_url. static SdchProblemCode CanSet(const std::string& domain, @@ -99,6 +108,19 @@ // Compare domains to see if the "match" for dictionary use. static bool DomainMatch(const GURL& url, const std::string& restriction); + // Is this dictionary expired? + bool Expired() const; + + void SetClockForTesting(scoped_ptr<base::Clock> clock); + + private: + friend class base::RefCountedData<Dictionary>; + + // Private copy-constructor to support RefCountedData<>, which requires + // that an object stored in it be either DefaultConstructible or + // CopyConstructible + Dictionary(const Dictionary& rhs); + // The actual text of the dictionary. std::string text_; @@ -118,7 +140,40 @@ const base::Time expiration_; // Implied by max-age. const std::set<int> ports_; - DISALLOW_COPY_AND_ASSIGN(Dictionary); + scoped_ptr<base::Clock> clock_; + + void operator=(const Dictionary&) = delete; + }; + + // A handle for one or more dictionaries which will keep the dictionaries + // alive and accessible for the handle's lifetime. + class NET_EXPORT_PRIVATE DictionarySet { + public: + ~DictionarySet(); + + // Return a comma separated list of client hashes. + std::string GetDictionaryClientHashList() const; + + // Lookup a given dictionary based on server hash. Returned pointer + // is guaranteed to be valid for the lifetime of the DictionarySet. + // Returns NULL if hash is not a valid server hash for a dictionary + // named by DictionarySet. + const SdchManager::Dictionary* GetDictionary(const std::string& hash) const; + + bool Empty() const; + + private: + // A DictionarySet may only be constructed by the SdchManager. + friend class SdchManager; + + DictionarySet(); + void AddDictionary(const std::string& server_hash, + const scoped_refptr<base::RefCountedData< + SdchManager::Dictionary>>& dictionary); + + DictionaryMap dictionaries_; + + DISALLOW_COPY_AND_ASSIGN(DictionarySet); }; SdchManager(); @@ -178,23 +233,22 @@ SdchProblemCode OnGetDictionary(const GURL& request_url, const GURL& dictionary_url); - // Find the vcdiff dictionary (the body of the sdch dictionary that appears - // after the meta-data headers like Domain:...) with the given |server_hash| - // to use to decompreses data that arrived as SDCH encoded content. Check to - // be sure the returned |dictionary| can be used for decoding content supplied - // in response to a request for |referring_url|. - // Return null in |dictionary| if there is no matching legal dictionary. - // Returns SDCH_OK if dictionary is not found, SDCH(-over-https) is disabled, - // or if matching legal dictionary exists. Otherwise returns the - // corresponding problem code. - SdchProblemCode GetVcdiffDictionary(const std::string& server_hash, - const GURL& referring_url, - scoped_refptr<Dictionary>* dictionary); + // Get a handle to the available dictionaries that might be used + // for encoding responses for the given URL. The return set will not + // include expired dictionaries. If no dictionaries + // are appropriate to use with the target_url, NULL is returned. + scoped_ptr<DictionarySet> GetDictionarySet(const GURL& target_url); - // Get list of available (pre-cached) dictionaries that we have already loaded - // into memory. The list is a comma separated list of (client) hashes per - // the SDCH spec. - void GetAvailDictionaryList(const GURL& target_url, std::string* list); + // Get a handle to a specific dictionary, by its server hash, confirming + // that that specific dictionary is appropriate to use with |target_url|. + // Expired dictionaries will be returned. If no dictionary with that + // hash exists that is usable with |target_url|, NULL is returned. + // If there is a usability problem, |*error_code| is set to the + // appropriate problem code. + scoped_ptr<DictionarySet> GetDictionarySetByHash( + const GURL& target_url, + const std::string& server_hash, + SdchProblemCode* problem_code); // Construct the pair of hashes for client and server to identify an SDCH // dictionary. This is only made public to facilitate unit testing, but is @@ -225,6 +279,8 @@ void AddObserver(SdchObserver* observer); void RemoveObserver(SdchObserver* observer); + static scoped_ptr<DictionarySet> CreateEmptyDictionarySetForTesting(); + private: struct BlacklistInfo { BlacklistInfo() : count(0), exponential_count(0), reason(SDCH_OK) {} @@ -233,18 +289,16 @@ int exponential_count; // Current exponential backoff ratchet. SdchProblemCode reason; // Why domain was blacklisted. }; + typedef std::map<std::string, BlacklistInfo> DomainBlacklistInfo; typedef std::set<std::string> ExperimentSet; // Determines whether a "Get-Dictionary" header is legal (dictionary // url has appropriate relationship to referrer url) in the SDCH - // protocol. Return SDCH_OK if fetch is legal. + // protocol. Return SDCH_OK if fetch is legal. SdchProblemCode CanFetchDictionary(const GURL& referring_url, const GURL& dictionary_url) const; - // A map of dictionaries info indexed by the hash that the server provides. - typedef std::map<std::string, scoped_refptr<Dictionary> > DictionaryMap; - // Support SDCH compression, by advertising in headers. static bool g_sdch_enabled_;
diff --git a/net/base/sdch_manager_unittest.cc b/net/base/sdch_manager_unittest.cc index c20be58..2b78394 100644 --- a/net/base/sdch_manager_unittest.cc +++ b/net/base/sdch_manager_unittest.cc
@@ -8,6 +8,8 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/strings/stringprintf.h" +#include "base/test/simple_test_clock.h" #include "net/base/net_log.h" #include "net/base/sdch_manager.h" #include "net/base/sdch_observer.h" @@ -199,12 +201,9 @@ EXPECT_TRUE(AddSdchDictionary(dictionary_text, GURL("http://" + dictionary_domain))); - std::string dictionary_list; // HTTP target URL can advertise dictionary. - sdch_manager()->GetAvailDictionaryList( - GURL("http://" + dictionary_domain + "/test"), - &dictionary_list); - EXPECT_FALSE(dictionary_list.empty()); + EXPECT_TRUE(sdch_manager()->GetDictionarySet( + GURL("http://" + dictionary_domain + "/test"))); } TEST_F(SdchManagerTest, CanNotAdvertiseDictionaryOverHTTPS) { @@ -214,12 +213,9 @@ EXPECT_TRUE(AddSdchDictionary(dictionary_text, GURL("http://" + dictionary_domain))); - std::string dictionary_list; // HTTPS target URL should NOT advertise dictionary. - sdch_manager()->GetAvailDictionaryList( - GURL("https://" + dictionary_domain + "/test"), - &dictionary_list); - EXPECT_TRUE(dictionary_list.empty()); + EXPECT_FALSE(sdch_manager()->GetDictionarySet( + GURL("https://" + dictionary_domain + "/test"))); } TEST_F(SdchManagerTest, CanUseHTTPSDictionaryOverHTTPSIfEnabled) { @@ -234,20 +230,21 @@ GURL("https://" + dictionary_domain))); GURL target_url("https://" + dictionary_domain + "/test"); - std::string dictionary_list; // HTTPS target URL should advertise dictionary if secure scheme support is // enabled. - sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list); - EXPECT_FALSE(dictionary_list.empty()); + EXPECT_TRUE(sdch_manager()->GetDictionarySet(target_url)); // Dictionary should be available. - scoped_refptr<SdchManager::Dictionary> dictionary; std::string client_hash; std::string server_hash; sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash); - EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary( - server_hash, target_url, &dictionary)); - EXPECT_TRUE(dictionary.get() != NULL); + SdchProblemCode problem_code; + scoped_ptr<SdchManager::DictionarySet> dict_set( + sdch_manager()->GetDictionarySetByHash( + target_url, server_hash, &problem_code)); + EXPECT_EQ(SDCH_OK, problem_code); + EXPECT_TRUE(dict_set.get()); + EXPECT_TRUE(dict_set->GetDictionary(server_hash)); } TEST_F(SdchManagerTest, CanNotUseHTTPDictionaryOverHTTPS) { @@ -258,21 +255,20 @@ GURL("http://" + dictionary_domain))); GURL target_url("https://" + dictionary_domain + "/test"); - std::string dictionary_list; // HTTPS target URL should not advertise dictionary acquired over HTTP even if // secure scheme support is enabled. SdchManager::EnableSecureSchemeSupport(true); - sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list); - EXPECT_TRUE(dictionary_list.empty()); + EXPECT_FALSE(sdch_manager()->GetDictionarySet(target_url)); - scoped_refptr<SdchManager::Dictionary> dictionary; std::string client_hash; std::string server_hash; sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash); - EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME, - sdch_manager()->GetVcdiffDictionary(server_hash, target_url, - &dictionary)); - EXPECT_TRUE(dictionary.get() == NULL); + SdchProblemCode problem_code; + scoped_ptr<SdchManager::DictionarySet> dict_set( + sdch_manager()->GetDictionarySetByHash( + target_url, server_hash, &problem_code)); + EXPECT_FALSE(dict_set.get()); + EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME, problem_code); } TEST_F(SdchManagerTest, CanNotUseHTTPSDictionaryOverHTTP) { @@ -284,20 +280,19 @@ GURL("https://" + dictionary_domain))); GURL target_url("http://" + dictionary_domain + "/test"); - std::string dictionary_list; // HTTP target URL should not advertise dictionary acquired over HTTPS even if // secure scheme support is enabled. - sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list); - EXPECT_TRUE(dictionary_list.empty()); + EXPECT_FALSE(sdch_manager()->GetDictionarySet(target_url)); - scoped_refptr<SdchManager::Dictionary> dictionary; std::string client_hash; std::string server_hash; sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash); - EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME, - sdch_manager()->GetVcdiffDictionary(server_hash, target_url, - &dictionary)); - EXPECT_TRUE(dictionary.get() == NULL); + SdchProblemCode problem_code; + scoped_ptr<SdchManager::DictionarySet> dict_set( + sdch_manager()->GetDictionarySetByHash( + target_url, server_hash, &problem_code)); + EXPECT_FALSE(dict_set.get()); + EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME, problem_code); } TEST_F(SdchManagerTest, FailToSetDomainMismatchDictionary) { @@ -438,7 +433,7 @@ EXPECT_TRUE(PathMatch("/search/", "/search/")); // Prefix only works if last character of restriction is a slash, or first - // character in path after a match is a slash. Validate each case separately. + // character in path after a match is a slash. Validate each case separately. // Rely on the slash in the path (not at the end of the restriction). EXPECT_TRUE(PathMatch("/search/something", "/search")); @@ -519,34 +514,36 @@ // can't get them from the other. EXPECT_TRUE(AddSdchDictionary(dictionary_text_1, GURL("http://" + dictionary_domain_1))); - scoped_refptr<SdchManager::Dictionary> dictionary; - EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary( - server_hash_1, - GURL("http://" + dictionary_domain_1 + "/random_url"), - &dictionary)); - EXPECT_TRUE(dictionary.get()); + scoped_ptr<SdchManager::DictionarySet> dict_set; + + SdchProblemCode problem_code; + dict_set = sdch_manager()->GetDictionarySetByHash( + GURL("http://" + dictionary_domain_1 + "/random_url"), + server_hash_1, &problem_code); + EXPECT_TRUE(dict_set); + EXPECT_TRUE(dict_set->GetDictionary(server_hash_1)); + EXPECT_EQ(SDCH_OK, problem_code); second_manager.AddSdchDictionary( dictionary_text_2, GURL("http://" + dictionary_domain_2)); - second_manager.GetVcdiffDictionary( - server_hash_2, + dict_set = second_manager.GetDictionarySetByHash( GURL("http://" + dictionary_domain_2 + "/random_url"), - &dictionary); - EXPECT_TRUE(dictionary.get()); + server_hash_2, &problem_code); + EXPECT_TRUE(dict_set); + EXPECT_TRUE(dict_set->GetDictionary(server_hash_2)); + EXPECT_EQ(SDCH_OK, problem_code); - EXPECT_EQ( - SDCH_DICTIONARY_HASH_NOT_FOUND, - sdch_manager()->GetVcdiffDictionary( - server_hash_2, GURL("http://" + dictionary_domain_2 + "/random_url"), - &dictionary)); - EXPECT_FALSE(dictionary.get()); + dict_set = sdch_manager()->GetDictionarySetByHash( + GURL("http://" + dictionary_domain_2 + "/random_url"), + server_hash_2, &problem_code); + EXPECT_FALSE(dict_set); + EXPECT_EQ(SDCH_DICTIONARY_HASH_NOT_FOUND, problem_code); - EXPECT_EQ( - SDCH_DICTIONARY_HASH_NOT_FOUND, - second_manager.GetVcdiffDictionary( - server_hash_1, GURL("http://" + dictionary_domain_1 + "/random_url"), - &dictionary)); - EXPECT_FALSE(dictionary.get()); + dict_set = second_manager.GetDictionarySetByHash( + GURL("http://" + dictionary_domain_1 + "/random_url"), + server_hash_1, &problem_code); + EXPECT_FALSE(dict_set); + EXPECT_EQ(SDCH_DICTIONARY_HASH_NOT_FOUND, problem_code); } TEST_F(SdchManagerTest, HttpsCorrectlySupported) { @@ -578,12 +575,16 @@ EXPECT_TRUE(AddSdchDictionary(dictionary_text, GURL("http://" + dictionary_domain))); - scoped_refptr<SdchManager::Dictionary> dictionary; - EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary( - server_hash, - GURL("http://" + dictionary_domain + "/random_url"), - &dictionary)); - EXPECT_TRUE(dictionary.get()); + + scoped_ptr<SdchManager::DictionarySet> dict_set; + + SdchProblemCode problem_code; + dict_set = sdch_manager()->GetDictionarySetByHash( + GURL("http://" + dictionary_domain + "/random_url"), + server_hash, &problem_code); + EXPECT_TRUE(dict_set); + EXPECT_TRUE(dict_set->GetDictionary(server_hash)); + EXPECT_EQ(SDCH_OK, problem_code); sdch_manager()->BlacklistDomain(GURL(blacklist_url), SDCH_OK); EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET, @@ -591,13 +592,11 @@ sdch_manager()->ClearData(); - dictionary = NULL; - EXPECT_EQ( - SDCH_DICTIONARY_HASH_NOT_FOUND, - sdch_manager()->GetVcdiffDictionary( - server_hash, GURL("http://" + dictionary_domain + "/random_url"), - &dictionary)); - EXPECT_FALSE(dictionary.get()); + dict_set = sdch_manager()->GetDictionarySetByHash( + GURL("http://" + dictionary_domain + "/random_url"), + server_hash, &problem_code); + EXPECT_FALSE(dict_set); + EXPECT_EQ(SDCH_DICTIONARY_HASH_NOT_FOUND, problem_code); EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(blacklist_url)); } @@ -620,4 +619,39 @@ EXPECT_EQ(test_dictionary_gurl, observer.last_dictionary_url()); } +TEST_F(SdchManagerTest, ExpirationCheckedProperly) { + // Create an SDCH dictionary with an expiration time in the past. + std::string dictionary_domain("x.y.z.google.com"); + std::string dictionary_text(base::StringPrintf( + "Domain: %s\nMax-age: 0\n\n", dictionary_domain.c_str())); + dictionary_text.append( + kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1); + std::string client_hash; + std::string server_hash; + SdchManager::GenerateHash(dictionary_text, &client_hash, &server_hash); + GURL target_gurl("http://" + dictionary_domain); + AddSdchDictionary(dictionary_text, target_gurl); + + // It should be visible if looked up by hash whether expired or not. + scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock); + clock->SetNow(base::Time::Now()); + clock->Advance(base::TimeDelta::FromMinutes(5)); + SdchProblemCode problem_code; + scoped_ptr<SdchManager::DictionarySet> hash_set( + sdch_manager()->GetDictionarySetByHash( + target_gurl, server_hash, &problem_code).Pass()); + ASSERT_TRUE(hash_set); + ASSERT_EQ(SDCH_OK, problem_code); + const_cast<SdchManager::Dictionary*>( + hash_set->GetDictionary(server_hash))->SetClockForTesting( + clock.Pass()); + + // Make sure it's not visible for advertisement, but is visible + // if looked up by hash. + EXPECT_FALSE(sdch_manager()->GetDictionarySet(target_gurl)); + EXPECT_TRUE(sdch_manager()->GetDictionarySetByHash( + target_gurl, server_hash, &problem_code)); + EXPECT_EQ(SDCH_OK, problem_code); +} + } // namespace net
diff --git a/net/base/sdch_problem_code_list.h b/net/base/sdch_problem_code_list.h index a0d5196..0eef912 100644 --- a/net/base/sdch_problem_code_list.h +++ b/net/base/sdch_problem_code_list.h
@@ -65,6 +65,10 @@ SDCH_PROBLEM_CODE(MULTIENCODING_FOR_NON_SDCH_REQUEST, 50) SDCH_PROBLEM_CODE(SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST, 51) +// A dictionary that wasn't advertised is being used for decoding. +SDCH_PROBLEM_CODE(UNADVERTISED_DICTIONARY_USED, 52) +SDCH_PROBLEM_CODE(UNADVERTISED_DICTIONARY_USED_CACHED, 53) + // Dictionary manager issues. SDCH_PROBLEM_CODE(DOMAIN_BLACKLIST_INCLUDES_TARGET, 61)
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc index c3f118d..cd9c9b8 100644 --- a/net/cookies/cookie_monster.cc +++ b/net/cookies/cookie_monster.cc
@@ -1319,16 +1319,12 @@ if (!HasCookieableScheme(url)) return std::string(); - TimeTicks start_time(TimeTicks::Now()); - std::vector<CanonicalCookie*> cookies; FindCookiesForHostAndDomain(url, options, true, &cookies); std::sort(cookies.begin(), cookies.end(), CookieSorter); std::string cookie_line = BuildCookieLine(cookies); - histogram_time_get_->AddTime(TimeTicks::Now() - start_time); - VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line; return cookie_line; @@ -2245,9 +2241,6 @@ base::Histogram::kUmaTargetedHistogramFlag); // From UMA_HISTOGRAM_{CUSTOM_,}TIMES - histogram_time_get_ = base::Histogram::FactoryTimeGet("Cookie.TimeGet", - base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), - 50, base::Histogram::kUmaTargetedHistogramFlag); histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet( "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h index 18d1b8a..0f00490 100644 --- a/net/cookies/cookie_monster.h +++ b/net/cookies/cookie_monster.h
@@ -635,7 +635,6 @@ base::HistogramBase* histogram_domain_per_etldp1_count_; base::HistogramBase* histogram_number_duplicate_db_cookies_; base::HistogramBase* histogram_cookie_deletion_cause_; - base::HistogramBase* histogram_time_get_; base::HistogramBase* histogram_time_mac_; base::HistogramBase* histogram_time_blocked_on_load_;
diff --git a/net/disk_cache/blockfile/in_flight_backend_io.cc b/net/disk_cache/blockfile/in_flight_backend_io.cc index 2cb3ff0..5b3b904 100644 --- a/net/disk_cache/blockfile/in_flight_backend_io.cc +++ b/net/disk_cache/blockfile/in_flight_backend_io.cc
@@ -341,35 +341,57 @@ } void InFlightBackendIO::Init(const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + // TODO(vadimt): Remove wrapping the callback with + // ScopedTracker::TrackCallback() once crbug.com/422516 is fixed. + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, + tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 InFlightBackendIO::Init"), + callback))); operation->Init(); PostOperation(operation.get()); } void InFlightBackendIO::OpenEntry(const std::string& key, Entry** entry, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::OpenEntry"), + callback))); operation->OpenEntry(key, entry); PostOperation(operation.get()); } void InFlightBackendIO::CreateEntry(const std::string& key, Entry** entry, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::CreateEntry"), + callback))); operation->CreateEntry(key, entry); PostOperation(operation.get()); } void InFlightBackendIO::DoomEntry(const std::string& key, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::DoomEntry"), + callback))); operation->DoomEntry(key); PostOperation(operation.get()); } void InFlightBackendIO::DoomAllEntries( const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::DoomAllEntries"), + callback))); operation->DoomAllEntries(); PostOperation(operation.get()); } @@ -377,14 +399,22 @@ void InFlightBackendIO::DoomEntriesBetween(const base::Time initial_time, const base::Time end_time, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::DoomEntriesBetween"), + callback))); operation->DoomEntriesBetween(initial_time, end_time); PostOperation(operation.get()); } void InFlightBackendIO::DoomEntriesSince( const base::Time initial_time, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::DoomEntriesSince"), + callback))); operation->DoomEntriesSince(initial_time); PostOperation(operation.get()); } @@ -392,7 +422,11 @@ void InFlightBackendIO::OpenNextEntry(Rankings::Iterator* iterator, Entry** next_entry, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::OpenNextEntry"), + callback))); operation->OpenNextEntry(iterator, next_entry); PostOperation(operation.get()); } @@ -427,14 +461,22 @@ } void InFlightBackendIO::FlushQueue(const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::FlushQueue"), + callback))); operation->FlushQueue(); PostOperation(operation.get()); } void InFlightBackendIO::RunTask( const base::Closure& task, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, + tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 InFlightBackendIO::RunTask"), + callback))); operation->RunTask(task); PostOperation(operation.get()); } @@ -442,7 +484,11 @@ void InFlightBackendIO::ReadData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::ReadData"), + callback))); operation->ReadData(entry, index, offset, buf, buf_len); PostOperation(operation.get()); } @@ -451,7 +497,11 @@ net::IOBuffer* buf, int buf_len, bool truncate, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::WriteData"), + callback))); operation->WriteData(entry, index, offset, buf, buf_len, truncate); PostOperation(operation.get()); } @@ -459,7 +509,11 @@ void InFlightBackendIO::ReadSparseData( EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::ReadSparseData"), + callback))); operation->ReadSparseData(entry, offset, buf, buf_len); PostOperation(operation.get()); } @@ -467,7 +521,11 @@ void InFlightBackendIO::WriteSparseData( EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::WriteSparseData"), + callback))); operation->WriteSparseData(entry, offset, buf, buf_len); PostOperation(operation.get()); } @@ -475,7 +533,11 @@ void InFlightBackendIO::GetAvailableRange( EntryImpl* entry, int64 offset, int len, int64* start, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::GetAvailableRange"), + callback))); operation->GetAvailableRange(entry, offset, len, start); PostOperation(operation.get()); } @@ -489,7 +551,11 @@ void InFlightBackendIO::ReadyForSparseIO( EntryImpl* entry, const net::CompletionCallback& callback) { - scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); + scoped_refptr<BackendIO> operation(new BackendIO( + this, backend_, tracked_objects::ScopedTracker::TrackCallback( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 InFlightBackendIO::CancelSparseIO"), + callback))); operation->ReadyForSparseIO(entry); PostOperation(operation.get()); }
diff --git a/net/disk_cache/simple/simple_util_win.cc b/net/disk_cache/simple/simple_util_win.cc index d0d191d..f2adcd0 100644 --- a/net/disk_cache/simple/simple_util_win.cc +++ b/net/disk_cache/simple/simple_util_win.cc
@@ -24,7 +24,7 @@ // Why a random name? Because if the name was derived from our original name, // then churn on a particular cache entry could cause flakey behaviour. - // TODO(gaivnp): Ensure these "todelete_" files are cleaned up on periodic + // TODO(gavinp): Ensure these "todelete_" files are cleaned up on periodic // directory sweeps. const base::FilePath rename_target = path.DirName().AppendASCII(base::StringPrintf("todelete_%016" PRIx64,
diff --git a/net/dns/dns_config_service_win_unittest.cc b/net/dns/dns_config_service_win_unittest.cc index 7ac01d1..54a6411 100644 --- a/net/dns/dns_config_service_win_unittest.cc +++ b/net/dns/dns_config_service_win_unittest.cc
@@ -55,7 +55,7 @@ IF_OPER_STATUS oper_status; const WCHAR* dns_suffix; std::string dns_server_addresses[4]; // Empty string indicates end. - int ports[4]; + uint16 ports[4]; }; scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> CreateAdapterAddresses( @@ -102,7 +102,7 @@ } IPAddressNumber ip; CHECK(ParseIPLiteralToNumber(info.dns_server_addresses[j], &ip)); - IPEndPoint ipe(ip, info.ports[j]); + IPEndPoint ipe = IPEndPoint(ip, info.ports[j]); address->Address.lpSockaddr = reinterpret_cast<LPSOCKADDR>(storage + num_addresses); socklen_t length = sizeof(struct sockaddr_storage); @@ -120,7 +120,7 @@ AdapterInfo input_adapters[4]; // |if_type| == 0 indicates end. std::string expected_nameservers[4]; // Empty string indicates end. std::string expected_suffix; - int expected_ports[4]; + uint16 expected_ports[4]; } cases[] = { { // Ignore loopback and inactive adapters. { @@ -181,7 +181,7 @@ for (size_t j = 0; !t.expected_nameservers[j].empty(); ++j) { IPAddressNumber ip; ASSERT_TRUE(ParseIPLiteralToNumber(t.expected_nameservers[j], &ip)); - int port = t.expected_ports[j]; + uint16 port = t.expected_ports[j]; if (!port) port = dns_protocol::kDefaultPort; expected_nameservers.push_back(IPEndPoint(ip, port));
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h index 2823c4b..0203dc9 100644 --- a/net/dns/host_resolver.h +++ b/net/dns/host_resolver.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "net/base/address_family.h" #include "net/base/completion_callback.h" @@ -67,7 +68,7 @@ host_port_pair_ = host_port_pair; } - int port() const { return host_port_pair_.port(); } + uint16 port() const { return host_port_pair_.port(); } const std::string& hostname() const { return host_port_pair_.host(); } AddressFamily address_family() const { return address_family_; }
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc index fe63820..9426da5 100644 --- a/net/dns/host_resolver_impl.cc +++ b/net/dns/host_resolver_impl.cc
@@ -300,14 +300,13 @@ #elif defined(OS_WIN) // Map the error code to a human-readable string. LPWSTR error_string = NULL; - int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - 0, // Use the internal message table. - os_error, - 0, // Use default language. - (LPWSTR)&error_string, - 0, // Buffer size. - 0); // Arguments (unused). + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + 0, // Use the internal message table. + os_error, + 0, // Use default language. + (LPWSTR)&error_string, + 0, // Buffer size. + 0); // Arguments (unused). dict->SetString("os_error_string", base::WideToUTF8(error_string)); LocalFree(error_string); #endif
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc index 7b6a391..7a46a1c 100644 --- a/net/dns/host_resolver_impl_unittest.cc +++ b/net/dns/host_resolver_impl_unittest.cc
@@ -181,7 +181,7 @@ }; bool AddressListContains(const AddressList& list, const std::string& address, - int port) { + uint16 port) { IPAddressNumber ip; bool rv = ParseIPLiteralToNumber(address, &ip); DCHECK(rv); @@ -249,7 +249,7 @@ bool completed() const { return result_ != ERR_IO_PENDING; } bool pending() const { return handle_ != NULL; } - bool HasAddress(const std::string& address, int port) const { + bool HasAddress(const std::string& address, uint16 port) const { return AddressListContains(list_, address, port); } @@ -258,7 +258,7 @@ return list_.size(); } - bool HasOneAddress(const std::string& address, int port) const { + bool HasOneAddress(const std::string& address, uint16 port) const { return HasAddress(address, port) && (NumberOfAddresses() == 1u); }
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc index 48e004e..6d8cba3 100644 --- a/net/dns/mock_host_resolver.cc +++ b/net/dns/mock_host_resolver.cc
@@ -48,7 +48,7 @@ LOG(WARNING) << "Not a supported IP literal: " << addresses[index]; return ERR_UNEXPECTED; } - addrlist->push_back(IPEndPoint(ip_number, -1)); + addrlist->push_back(IPEndPoint(ip_number, 0)); } return OK; }
diff --git a/net/filter/filter.cc b/net/filter/filter.cc index 53d6583..b3f98cb 100644 --- a/net/filter/filter.cc +++ b/net/filter/filter.cc
@@ -3,20 +3,20 @@ // found in the LICENSE file. // The basic usage of the Filter interface is described in the comment at -// the beginning of filter.h. If Filter::Factory is passed a vector of +// the beginning of filter.h. If Filter::Factory is passed a vector of // size greater than 1, that interface is implemented by a series of filters -// connected in a chain. In such a case the first filter +// connected in a chain. In such a case the first filter // in the chain proxies calls to ReadData() so that its return values // apply to the entire chain. // // In a filter chain, the data flows from first filter (held by the -// caller) down the chain. When ReadData() is called on any filter +// caller) down the chain. When ReadData() is called on any filter // except for the last filter, it proxies the call down the chain, // filling in the input buffers of subsequent filters if needed (== // that filter's last_status() value is FILTER_NEED_MORE_DATA) and -// available (== the current filter has data it can output). The last +// available (== the current filter has data it can output). The last // Filter will then output data if possible, and return -// FILTER_NEED_MORE_DATA if not. Because the indirection pushes +// FILTER_NEED_MORE_DATA if not. Because the indirection pushes // data along the filter chain at each level if it's available and the // next filter needs it, a return value of FILTER_NEED_MORE_DATA from the // final filter will apply to the entire chain. @@ -43,8 +43,8 @@ const char kGZip[] = "gzip"; const char kXGZip[] = "x-gzip"; const char kSdch[] = "sdch"; -// compress and x-compress are currently not supported. If we decide to support -// them, we'll need the same mime type compatibility hack we have for gzip. For +// compress and x-compress are currently not supported. If we decide to support +// them, we'll need the same mime type compatibility hack we have for gzip. For // more information, see Firefox's nsHttpChannel::ProcessNormal. // Mime types: @@ -153,9 +153,9 @@ // In the case where this filter has data internally, and is indicating such // with a last_status_ of FILTER_OK, but at the same time the next filter in // the chain indicated it FILTER_NEED_MORE_DATA, we have to be cautious - // about confusing the caller. The API confusion can appear if we return + // about confusing the caller. The API confusion can appear if we return // FILTER_OK (suggesting we have more data in aggregate), but yet we don't - // populate our output buffer. When that is the case, we need to + // populate our output buffer. When that is the case, we need to // alternately call our filter element, and the next_filter element until we // get out of this state (by pumping data into the next filter until it // outputs data, or it runs out of data and reports that it NEED_MORE_DATA.) @@ -217,8 +217,8 @@ LowerCaseEqualsASCII(mime_type, kApplicationGzip) || LowerCaseEqualsASCII(mime_type, kApplicationXGunzip)) // The server has told us that it sent us gziped content with a gzip - // content encoding. Sadly, Apache mistakenly sets these headers for all - // .gz files. We match Firefox's nsHttpChannel::ProcessNormal and ignore + // content encoding. Sadly, Apache mistakenly sets these headers for all + // .gz files. We match Firefox's nsHttpChannel::ProcessNormal and ignore // the Content-Encoding here. encoding_types->clear(); @@ -256,7 +256,7 @@ } // If the request was for SDCH content, then we might need additional fixups. - if (!filter_context.SdchResponseExpected()) { + if (!filter_context.SdchDictionariesAdvertised()) { // It was not an SDCH request, so we'll just record stats. if (1 < encoding_types->size()) { // Multiple filters were intended to only be used for SDCH (thus far!) @@ -271,7 +271,7 @@ } // The request was tagged as an SDCH request, which means the server supplied - // a dictionary, and we advertised it in the request. Some proxies will do + // a dictionary, and we advertised it in the request. Some proxies will do // very strange things to the request, or the response, so we have to handle // them gracefully. @@ -280,7 +280,7 @@ (FILTER_TYPE_SDCH == encoding_types->front())) { // Some proxies (found currently in Argentina) strip the Content-Encoding // text from "sdch,gzip" to a mere "sdch" without modifying the compressed - // payload. To handle this gracefully, we simulate the "probably" deleted + // payload. To handle this gracefully, we simulate the "probably" deleted // ",gzip" by appending a tentative gzip decode, which will default to a // no-op pass through filter if it doesn't get gzip headers where expected. if (1 == encoding_types->size()) { @@ -290,20 +290,20 @@ return; } - // There are now several cases to handle for an SDCH request. Foremost, if + // There are now several cases to handle for an SDCH request. Foremost, if // the outbound request was stripped so as not to advertise support for // encodings, we might get back content with no encoding, or (for example) - // just gzip. We have to be sure that any changes we make allow for such - // minimal coding to work. That issue is why we use TENTATIVE filters if we + // just gzip. We have to be sure that any changes we make allow for such + // minimal coding to work. That issue is why we use TENTATIVE filters if we // add any, as those filters sniff the content, and act as pass-through // filters if headers are not found. // If the outbound GET is not modified, then the server will generally try to - // send us SDCH encoded content. As that content returns, there are several + // send us SDCH encoded content. As that content returns, there are several // corruptions of the header "content-encoding" that proxies may perform (and - // have been detected in the wild). We already dealt with the a honest + // have been detected in the wild). We already dealt with the a honest // content encoding of "sdch,gzip" being corrupted into "sdch" with on change - // of the actual content. Another common corruption is to either disscard + // of the actual content. Another common corruption is to either disscard // the accurate content encoding, or to replace it with gzip only (again, with // no change in actual content). The last observed corruption it to actually // change the content, such as by re-gzipping it, and that may happen along @@ -328,7 +328,7 @@ } else { // Remarkable case!?! We advertised an SDCH dictionary, content-encoding // was not marked for SDCH processing: Why did the server suggest an SDCH - // dictionary in the first place??. Also, the content isn't + // dictionary in the first place??. Also, the content isn't // tagged as HTML, despite the fact that SDCH encoding is mostly likely for // HTML: Did some anti-virus system strip this tag (sometimes they strip // accept-encoding headers on the request)?? Does the content encoding not @@ -344,9 +344,9 @@ } // Leave the existing encoding type to be processed first, and add our - // tentative decodings to be done afterwards. Vodaphone UK reportedyl will + // tentative decodings to be done afterwards. Vodaphone UK reportedyl will // perform a second layer of gzip encoding atop the server's sdch,gzip - // encoding, and then claim that the content encoding is a mere gzip. As a + // encoding, and then claim that the content encoding is a mere gzip. As a // result we'll need (in that case) to do the gunzip, plus our tentative // gunzip and tentative SDCH decoding. // This approach nicely handles the empty() list as well, and should work with
diff --git a/net/filter/filter.h b/net/filter/filter.h index cec8398..428dc8c 100644 --- a/net/filter/filter.h +++ b/net/filter/filter.h
@@ -20,22 +20,22 @@ // through its accessor and fills in stream_buffer_ with pre-filter data, next // calls FlushStreamBuffer to notify Filter, then calls ReadFilteredData // repeatedly to get all the filtered data. After all data have been filtered -// and read out, the caller may fill in stream_buffer_ again. This +// and read out, the caller may fill in stream_buffer_ again. This // WriteBuffer-Flush-Read cycle is repeated until reaching the end of data // stream. // // A return of FILTER_OK from ReadData() means that more data is // available to a future ReadData() call and data may not be written -// into stream_buffer(). A return of FILTER_NEED_MORE_DATA from ReadData() +// into stream_buffer(). A return of FILTER_NEED_MORE_DATA from ReadData() // indicates that no data will be forthcoming from the filter until // it receives more input data, and that the buffer at // stream_buffer() may be written to. // // The filter being complete (no more data to provide) may be indicated // by either returning FILTER_DONE or by returning FILTER_OK and indicating -// zero bytes output; consumers understand both those signals. Consumers +// zero bytes output; consumers understand both those signals. Consumers // are responsible for not calling ReadData() on a filter after one of these -// signals have been returned. Note that some filters may never signal that +// signals have been returned. Note that some filters may never signal that // they are done (e.g. a pass-through filter will always // say FILTER_NEED_MORE_DATA), so the consumer will also need to // recognize the state of |no_more_input_data_available && @@ -55,6 +55,7 @@ #include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "net/base/net_export.h" +#include "net/base/sdch_manager.h" class GURL; @@ -66,11 +67,19 @@ //------------------------------------------------------------------------------ // Define an interface class that allows access to contextual information -// supplied by the owner of this filter. In the case where there are a chain of +// supplied by the owner of this filter. In the case where there are a chain of // filters, there is only one owner of all the chained filters, and that context -// is passed to the constructor of all those filters. To be clear, the context +// is passed to the constructor of all those filters. To be clear, the context // does NOT reflect the position in a chain, or the fact that there are prior // or later filters in a chain. +// +// TODO(rdsmith): FilterContext is a grab-bag of methods which may or may +// not be relevant for any particular filter, and it's getting worse over +// time. In addition, it only supports two filters, SDCH and gzip. +// It would make more sense to implement FilterContext as a +// base::SupportsUserData structure to which filter-specific information +// could be added by whatever the ultimate consumer of the filter chain is, +// and a particular filter (if included) could access that information. class NET_EXPORT_PRIVATE FilterContext { public: // Enum to control what histograms are emitted near end-of-life of this @@ -107,14 +116,14 @@ virtual bool IsDownload() const = 0; // Was this data flagged as a response to a request with an SDCH dictionary? - virtual bool SdchResponseExpected() const = 0; + virtual SdchManager::DictionarySet* SdchDictionariesAdvertised() const = 0; // How many bytes were read from the net or cache so far (and potentially // pushed into a filter for processing)? virtual int64 GetByteReadCount() const = 0; // What response code was received with the associated network transaction? - // For example: 200 is ok. 4xx are error codes. etc. + // For example: 200 is ok. 4xx are error codes. etc. virtual int GetResponseCode() const = 0; // The URLRequestContext associated with the request. @@ -137,7 +146,7 @@ FILTER_OK, // Read filtered data successfully, and the data in the buffer has been // consumed by the filter, but more data is needed in order to continue - // filtering. At this point, the caller is free to reuse the filter + // filtering. At this point, the caller is free to reuse the filter // buffer to provide more data. FILTER_NEED_MORE_DATA, // Read filtered data successfully, and filter reaches the end of the data @@ -169,7 +178,7 @@ // // Note: filter_types is an array of filter types (content encoding types as // provided in an HTTP header), which will be chained together serially to do - // successive filtering of data. The types in the vector are ordered based on + // successive filtering of data. The types in the vector are ordered based on // encoding order, and the filters are chained to operate in the reverse // (decoding) order. For example, types[0] = FILTER_TYPE_SDCH, // types[1] = FILTER_TYPE_GZIP will cause data to first be gunzip filtered, @@ -182,7 +191,7 @@ // initialized. static Filter* GZipFactory(); - // External call to obtain data from this filter chain. If ther is no + // External call to obtain data from this filter chain. If ther is no // next_filter_, then it obtains data from this specific filter. FilterStatus ReadData(char* dest_buffer, int* dest_len); @@ -216,10 +225,10 @@ static FilterType ConvertEncodingToType(const std::string& filter_type); // Given a array of encoding_types, try to do some error recovery adjustment - // to the list. This includes handling known bugs in the Apache server (where + // to the list. This includes handling known bugs in the Apache server (where // redundant gzip encoding is specified), as well as issues regarding SDCH // encoding, where various proxies and anti-virus products modify or strip the - // encodings. These fixups require context, which includes whether this + // encodings. These fixups require context, which includes whether this // response was made to an SDCH request (i.e., an available dictionary was // advertised in the GET), as well as the mime type of the content. static void FixupEncodingTypes(const FilterContext& filter_context, @@ -270,8 +279,8 @@ void InitBuffer(int size); // A factory helper for creating filters for within a chain of potentially - // multiple encodings. If a chain of filters is created, then this may be - // called multiple times during the filter creation process. In most simple + // multiple encodings. If a chain of filters is created, then this may be + // called multiple times during the filter creation process. In most simple // cases, this is only called once. Returns NULL and cleans up (deleting // filter_list) if a new filter can't be constructed. static Filter* PrependNewFilter(FilterType type_id,
diff --git a/net/filter/filter_unittest.cc b/net/filter/filter_unittest.cc index 5b2446c..fcedeaf 100644 --- a/net/filter/filter_unittest.cc +++ b/net/filter/filter_unittest.cc
@@ -24,9 +24,6 @@ } // namespace -class FilterTest : public testing::Test { -}; - TEST(FilterTest, ContentTypeId) { // Check for basic translation of Content-Encoding, including case variations. EXPECT_EQ(Filter::FILTER_TYPE_DEFLATE, @@ -54,7 +51,7 @@ // Check various fixups that modify content encoding lists. TEST(FilterTest, ApacheGzip) { MockFilterContext filter_context; - filter_context.SetSdchResponse(false); + filter_context.SetSdchResponse(NULL); // Check that redundant gzip mime type removes only solo gzip encoding. const std::string kGzipMime1("application/x-gzip"); @@ -100,7 +97,7 @@ TEST(FilterTest, GzipContentDispositionFilename) { MockFilterContext filter_context; - filter_context.SetSdchResponse(false); + filter_context.SetSdchResponse(NULL); const std::string kGzipMime("application/x-tar"); const std::string kContentDisposition("attachment; filename=\"foo.tgz\""); @@ -119,7 +116,9 @@ // Handle content encodings including SDCH. const std::string kTextHtmlMime("text/html"); MockFilterContext filter_context; - filter_context.SetSdchResponse(true); + // Empty handle indicates to filter that SDCH is active. + filter_context.SetSdchResponse( + SdchManager::CreateEmptyDictionarySetForTesting().Pass()); std::vector<Filter::FilterType> encoding_types; @@ -156,7 +155,8 @@ // Handle interesting case where entire SDCH encoding assertion "got lost." const std::string kTextHtmlMime("text/html"); MockFilterContext filter_context; - filter_context.SetSdchResponse(true); + filter_context.SetSdchResponse( + SdchManager::CreateEmptyDictionarySetForTesting().Pass()); std::vector<Filter::FilterType> encoding_types; @@ -169,7 +169,7 @@ EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH, encoding_types[1]); // Loss of encoding, but it was an SDCH response with a prefix that says it - // was an html type. Note that it *should* be the case that a precise match + // was an html type. Note that it *should* be the case that a precise match // with "text/html" we be collected by GetMimeType() and passed in, but we // coded the fixup defensively (scanning for a prefix of "text/html", so this // is an example which could survive such confusion in the caller).
diff --git a/net/filter/mock_filter_context.cc b/net/filter/mock_filter_context.cc index 35ab9ee..67012de 100644 --- a/net/filter/mock_filter_context.cc +++ b/net/filter/mock_filter_context.cc
@@ -11,7 +11,6 @@ MockFilterContext::MockFilterContext() : is_cached_content_(false), is_download_(false), - is_sdch_response_(false), ok_to_call_get_url_(true), response_code_(-1), context_(new URLRequestContext()) { @@ -54,8 +53,9 @@ bool MockFilterContext::IsDownload() const { return is_download_; } -bool MockFilterContext::SdchResponseExpected() const { - return is_sdch_response_; +SdchManager::DictionarySet* +MockFilterContext::SdchDictionariesAdvertised() const { + return dictionaries_handle_.get(); } int64 MockFilterContext::GetByteReadCount() const { return 0; }
diff --git a/net/filter/mock_filter_context.h b/net/filter/mock_filter_context.h index 41c9e9e..776a237 100644 --- a/net/filter/mock_filter_context.h +++ b/net/filter/mock_filter_context.h
@@ -9,6 +9,7 @@ #include "base/memory/scoped_ptr.h" #include "net/base/net_log.h" +#include "net/base/sdch_manager.h" #include "net/filter/filter.h" #include "url/gurl.h" @@ -30,15 +31,15 @@ void SetCached(bool is_cached) { is_cached_content_ = is_cached; } void SetDownload(bool is_download) { is_download_ = is_download; } void SetResponseCode(int response_code) { response_code_ = response_code; } - void SetSdchResponse(bool is_sdch_response) { - is_sdch_response_ = is_sdch_response; + void SetSdchResponse(scoped_ptr<SdchManager::DictionarySet> handle) { + dictionaries_handle_ = handle.Pass(); } URLRequestContext* GetModifiableURLRequestContext() const { return context_.get(); } // After a URLRequest's destructor is called, some interfaces may become - // unstable. This method is used to signal that state, so we can tag use + // unstable. This method is used to signal that state, so we can tag use // of those interfaces as coding errors. void NukeUnstableInterfaces(); @@ -61,8 +62,8 @@ // Is this a download? bool IsDownload() const override; - // Was this data flagged as a response to a request with an SDCH dictionary? - bool SdchResponseExpected() const override; + // Handle to dictionaries advertised. + SdchManager::DictionarySet* SdchDictionariesAdvertised() const override; // How many bytes were fed to filter(s) so far? int64 GetByteReadCount() const override; @@ -84,7 +85,7 @@ base::Time request_time_; bool is_cached_content_; bool is_download_; - bool is_sdch_response_; + scoped_ptr<SdchManager::DictionarySet> dictionaries_handle_; bool ok_to_call_get_url_; int response_code_; scoped_ptr<URLRequestContext> context_;
diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc index d1eb7f4..30392cd 100644 --- a/net/filter/sdch_filter.cc +++ b/net/filter/sdch_filter.cc
@@ -14,6 +14,7 @@ #include "base/values.h" #include "net/base/sdch_manager.h" #include "net/base/sdch_net_log_params.h" +#include "net/base/sdch_problem_codes.h" #include "net/url_request/url_request_context.h" #include "sdch/open-vcdiff/src/google/vcdecoder.h" @@ -251,12 +252,12 @@ // advertisement (so that we are sure we're not hurting anything). // // Watch out for an error page inserted by the proxy as part of a 40x - // error response. When we see such content molestation, we certainly + // error response. When we see such content molestation, we certainly // need to fall into the meta-refresh case. ResponseCorruptionDetectionCause cause = RESPONSE_NONE; if (filter_context_.GetResponseCode() == 404) { // We could be more generous, but for now, only a "NOT FOUND" code will - // cause a pass through. All other bad codes will fall into a + // cause a pass through. All other bad codes will fall into a // meta-refresh. LogSdchProblem(SDCH_PASS_THROUGH_404_CODE); cause = RESPONSE_404; @@ -276,13 +277,13 @@ // error. We were just overly cautious when we added a TENTATIVE_SDCH. // We added the sdch coding tag, and it should not have been added. // This can happen in server experiments, where the server decides - // not to use sdch, even though there is a dictionary. To be + // not to use sdch, even though there is a dictionary. To be // conservative, we locally added the tentative sdch (fearing that a // proxy stripped it!) and we must now recant (pass through). // // However.... just to be sure we don't get burned by proxies that // re-compress with gzip or other system, we can sniff to see if this - // is compressed data etc. For now, we do nothing, which gets us into + // is compressed data etc. For now, we do nothing, which gets us into // the meta-refresh result. // TODO(jar): Improve robustness by sniffing for valid text that we can // actual use re: decoding_status_ = PASS_THROUGH; @@ -292,8 +293,8 @@ // The common cause is a restart of the browser, where we try to render // cached content that was saved when we had a dictionary. cause = RESPONSE_NO_DICTIONARY; - } else if (filter_context_.SdchResponseExpected()) { - // This is a very corrupt SDCH request response. We can't decode it. + } else if (filter_context_.SdchDictionariesAdvertised()) { + // This is a very corrupt SDCH request response. We can't decode it. // We'll use a meta-refresh, and get content without asking for SDCH. // This will also progressively disable SDCH for this domain. cause = RESPONSE_CORRUPT_SDCH; @@ -377,7 +378,7 @@ if (decoding_status_ != DECODING_IN_PROGRESS) { if (META_REFRESH_RECOVERY == decoding_status_) { - // Absorb all input data. We've already output page reload HTML. + // Absorb all input data. We've already output page reload HTML. next_stream_data_ = NULL; stream_data_len_ = 0; return FILTER_NEED_MORE_DATA; @@ -441,25 +442,52 @@ else next_stream_data_ = NULL; - DCHECK(!dictionary_.get()); + DCHECK(!dictionary_); dictionary_hash_is_plausible_ = true; // Assume plausible, but check. SdchProblemCode rv = SDCH_OK; if ('\0' == dictionary_hash_[kServerIdLength - 1]) { - SdchManager* manager(url_request_context_->sdch_manager()); - rv = manager->GetVcdiffDictionary( - std::string(dictionary_hash_, 0, kServerIdLength - 1), url_, - &dictionary_); - if (rv == SDCH_DICTIONARY_HASH_NOT_FOUND) { - DCHECK(dictionary_hash_.size() == kServerIdLength); - // Since dictionary was not found, check to see if hash was even - // plausible. - for (size_t i = 0; i < kServerIdLength - 1; ++i) { - char base64_char = dictionary_hash_[i]; - if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) { - rv = SDCH_DICTIONARY_HASH_MALFORMED; - dictionary_hash_is_plausible_ = false; - break; + std::string server_hash(dictionary_hash_, 0, kServerIdLength - 1); + SdchManager::DictionarySet* handle = + filter_context_.SdchDictionariesAdvertised(); + if (handle) + dictionary_ = handle->GetDictionary(server_hash); + if (!dictionary_) { + // This is a hack. Naively, the dictionaries available for + // decoding should be only the ones advertised. However, there are + // cases, specifically resources encoded with old dictionaries living + // in the cache, that mean the full set of dictionaries should be made + // available for decoding. It's not known how often this happens; + // if it happens rarely enough, this code can be removed. + // + // TODO(rdsmith): Long-term, a better solution is necessary, since + // an entry in the cache being encoded with the dictionary doesn't + // guarantee that the dictionary is present. That solution probably + // involves storing unencoded resources in the cache, but might + // involve evicting encoded resources on dictionary removal. + // See http://crbug.com/383405. + unexpected_dictionary_handle_ = + url_request_context_->sdch_manager()->GetDictionarySetByHash( + url_, server_hash, &rv); + if (unexpected_dictionary_handle_) { + dictionary_ = unexpected_dictionary_handle_->GetDictionary(server_hash); + // Override SDCH_OK rv; this is still worth logging. + rv = (filter_context_.IsCachedContent() ? + SDCH_UNADVERTISED_DICTIONARY_USED_CACHED : + SDCH_UNADVERTISED_DICTIONARY_USED); + } else { + // Since dictionary was not found, check to see if hash was + // even plausible. + DCHECK(dictionary_hash_.size() == kServerIdLength); + rv = SDCH_DICTIONARY_HASH_NOT_FOUND; + for (size_t i = 0; i < kServerIdLength - 1; ++i) { + char base64_char = dictionary_hash_[i]; + if (!isalnum(base64_char) && + '-' != base64_char && '_' != base64_char) { + dictionary_hash_is_plausible_ = false; + rv = SDCH_DICTIONARY_HASH_MALFORMED; + break; + } } } } @@ -467,12 +495,15 @@ dictionary_hash_is_plausible_ = false; rv = SDCH_DICTIONARY_HASH_MALFORMED; } - if (rv != SDCH_OK) { + + if (rv != SDCH_OK) LogSdchProblem(rv); + + if (!dictionary_) { decoding_status_ = DECODING_ERROR; return FILTER_ERROR; } - DCHECK(dictionary_.get()); + vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder); vcdiff_streaming_decoder_->SetAllowVcdTarget(false); vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(),
diff --git a/net/filter/sdch_filter.h b/net/filter/sdch_filter.h index bc7788c..9541742 100644 --- a/net/filter/sdch_filter.h +++ b/net/filter/sdch_filter.h
@@ -43,7 +43,7 @@ FilterStatus ReadFilteredData(char* dest_buffer, int* dest_len) override; private: - // Internal status. Once we enter an error state, we stop processing data. + // Internal status. Once we enter an error state, we stop processing data. enum DecodingStatus { DECODING_UNINITIALIZED, WAITING_FOR_DICTIONARY_SELECTION, @@ -87,19 +87,19 @@ // After assembling an entire dictionary hash (the first 9 bytes of the // sdch payload, we check to see if it is plausible, meaning it has a null // termination, and has 8 characters that are possible in a net-safe base64 - // encoding. If the hash is not plausible, then the payload is probably not + // encoding. If the hash is not plausible, then the payload is probably not // an SDCH encoded bundle, and various error recovery strategies can be // attempted. bool dictionary_hash_is_plausible_; - // We hold an in-memory copy of the dictionary during the entire decoding, as - // it is used directly by the VC-DIFF decoding system. - // That char* data is part of the dictionary_ we hold a reference to. - scoped_refptr<SdchManager::Dictionary> dictionary_; + // Validity of this pointer is guaranteed by either the FilterContext holding + // a containing SdchManager::DictionarySet, or this object holding a + // container in |unexpected_dictionary_handle_| below. + const SdchManager::Dictionary *dictionary_; // We keep a copy of the URLRequestContext for use in the destructor, (at // which point GetURLRequestContext() will likely return null because of - // the disassociation of the URLRequest from the URLRequestJob). This is + // the disassociation of the URLRequest from the URLRequestJob). This is // safe because the URLRequestJob (and any filters) are guaranteed to be // deleted before the URLRequestContext is destroyed. const URLRequestContext* const url_request_context_; @@ -129,6 +129,11 @@ // by checking within this mime type (we may do a meta-refresh via html). std::string mime_type_; + // If the response was encoded with a dictionary different than those + // advertised (e.g. a cached response using an old dictionary), this + // variable preserves that dictionary from deletion during decoding. + scoped_ptr<SdchManager::DictionarySet> unexpected_dictionary_handle_; + DISALLOW_COPY_AND_ASSIGN(SdchFilter); };
diff --git a/net/filter/sdch_filter_unittest.cc b/net/filter/sdch_filter_unittest.cc index 79b5673..be9790d 100644 --- a/net/filter/sdch_filter_unittest.cc +++ b/net/filter/sdch_filter_unittest.cc
@@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/test/simple_test_clock.h" #include "net/base/io_buffer.h" #include "net/filter/mock_filter_context.h" #include "net/filter/sdch_filter.h" @@ -25,12 +26,12 @@ // Note an SDCH dictionary has extra meta-data before the VCDIFF dictionary. static const char kTestVcdiffDictionary[] = "DictionaryFor" "SdchCompression1SdchCompression2SdchCompression3SdchCompression\n"; -// Pre-compression test data. Note that we pad with a lot of highly gzip -// compressible content to help to exercise the chaining pipeline. That is why +// Pre-compression test data. Note that we pad with a lot of highly gzip +// compressible content to help to exercise the chaining pipeline. That is why // there are a PILE of zeros at the start and end. // This will ensure that gzip compressed data can be fed to the chain in one // gulp, but (with careful selection of intermediate buffers) that it takes -// several sdch buffers worth of data to satisfy the sdch filter. See detailed +// several sdch buffers worth of data to satisfy the sdch filter. See detailed // CHECK() calls in FilterChaining test for specifics. static const char kTestData[] = "0000000000000000000000000000000000000000000000" "0000000000000000000000000000TestData " @@ -63,8 +64,8 @@ url_request_context->set_sdch_manager(sdch_manager_.get()); } - // Attempt to add a dictionary to the manager; returns whether or not - // the attempt succeeded. + // Attempt to add a dictionary to the manager and probe for success or + // failure. bool AddSdchDictionary(const std::string& dictionary_text, const GURL& gurl) { return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK; @@ -72,6 +73,13 @@ MockFilterContext* filter_context() { return filter_context_.get(); } + // Sets both the GURL and the SDCH response for a filter context. + void SetupFilterContextWithGURL(GURL url) { + filter_context_->SetURL(url); + filter_context_->SetSdchResponse( + sdch_manager_->GetDictionarySet(url).Pass()); + } + std::string NewSdchCompressedData(const std::string dictionary) { std::string client_hash; std::string server_hash; @@ -108,11 +116,11 @@ //------------------------------------------------------------------------------ // Provide a generic helper function for trying to filter data. // This function repeatedly calls the filter to process data, until the entire -// source is consumed. The return value from the filter is appended to output. +// source is consumed. The return value from the filter is appended to output. // This allows us to vary input and output block sizes in order to test for edge // effects (boundary effects?) during the filtering process. // This function provides data to the filter in blocks of no-more-than the -// specified input_block_length. It allows the filter to fill no more than +// specified input_block_length. It allows the filter to fill no more than // output_buffer_length in any one call to proccess (a.k.a., Read) data, and // concatenates all these little output blocks into the singular output string. static bool FilterTestData(const std::string& source, @@ -159,6 +167,19 @@ return dictionary; } +static std::string NewSdchExpiredDictionary(const std::string& domain) { + std::string dictionary; + if (!domain.empty()) { + dictionary.append("Domain: "); + dictionary.append(domain); + dictionary.append("\n"); + } + dictionary.append("Max-Age: 0\n"); + dictionary.append("\n"); + dictionary.append(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1); + return dictionary; +} + //------------------------------------------------------------------------------ TEST_F(SdchFilterTest, EmptyInputOk) { @@ -197,10 +218,10 @@ EXPECT_EQ(0, output_bytes_or_buffer_size); EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status); - // Partially tear down context. Anything that goes through request() + // Partially tear down context. Anything that goes through request() // without checking it for null in the URLRequestJob::HttpFilterContext - // implementation is suspect. Everything that does check it for null should - // return null. This is to test for incorrectly relying on filter_context() + // implementation is suspect. Everything that does check it for null should + // return null. This is to test for incorrectly relying on filter_context() // from the SdchFilter destructor. filter_context()->NukeUnstableInterfaces(); } @@ -451,7 +472,7 @@ std::vector<Filter::FilterType> filter_types; filter_types.push_back(Filter::FILTER_TYPE_SDCH); - filter_context()->SetURL(url); + SetupFilterContextWithGURL(url); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); @@ -488,7 +509,8 @@ std::vector<Filter::FilterType> filter_types; filter_types.push_back(Filter::FILTER_TYPE_SDCH); - filter_context()->SetURL(GURL("https://" + kSampleDomain)); + GURL filter_context_gurl("https://" + kSampleDomain); + SetupFilterContextWithGURL(GURL("https://" + kSampleDomain)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); const size_t feed_block_size(100); @@ -501,7 +523,7 @@ // Current failsafe TODO/hack refuses to decode any content that doesn't use // http as the scheme (see use of DICTIONARY_SELECTED_FOR_NON_HTTP). -// The following tests this blockage. Note that blacklisting results, so we +// The following tests this blockage. Note that blacklisting results, so we // we need separate tests for each of these. TEST_F(SdchFilterTest, NoDecodeFtp) { // Construct a valid SDCH dictionary from a VCDIFF dictionary. @@ -518,7 +540,7 @@ std::vector<Filter::FilterType> filter_types; filter_types.push_back(Filter::FILTER_TYPE_SDCH); - filter_context()->SetURL(GURL("ftp://" + kSampleDomain)); + SetupFilterContextWithGURL(GURL("ftp://" + kSampleDomain)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); const size_t feed_block_size(100); @@ -544,7 +566,7 @@ std::vector<Filter::FilterType> filter_types; filter_types.push_back(Filter::FILTER_TYPE_SDCH); - filter_context()->SetURL(GURL("file://" + kSampleDomain)); + SetupFilterContextWithGURL(GURL("file://" + kSampleDomain)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); const size_t feed_block_size(100); @@ -570,7 +592,7 @@ std::vector<Filter::FilterType> filter_types; filter_types.push_back(Filter::FILTER_TYPE_SDCH); - filter_context()->SetURL(GURL("about://" + kSampleDomain)); + SetupFilterContextWithGURL(GURL("about://" + kSampleDomain)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); const size_t feed_block_size(100); @@ -596,7 +618,7 @@ std::vector<Filter::FilterType> filter_types; filter_types.push_back(Filter::FILTER_TYPE_SDCH); - filter_context()->SetURL(GURL("javascript://" + kSampleDomain)); + SetupFilterContextWithGURL(GURL("javascript://" + kSampleDomain)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); const size_t feed_block_size(100); @@ -622,7 +644,7 @@ std::vector<Filter::FilterType> filter_types; filter_types.push_back(Filter::FILTER_TYPE_SDCH); - filter_context()->SetURL(GURL("http://" + kSampleDomain)); + SetupFilterContextWithGURL(GURL("http://" + kSampleDomain)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); const size_t feed_block_size(100); @@ -651,7 +673,7 @@ // Decode with content arriving from the "wrong" domain. // This tests SdchManager::CanSet(). GURL wrong_domain_url("http://www.wrongdomain.com"); - filter_context()->SetURL(wrong_domain_url); + SetupFilterContextWithGURL(wrong_domain_url); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); size_t feed_block_size = 100; @@ -696,7 +718,7 @@ filter_types.push_back(Filter::FILTER_TYPE_SDCH); // Test decode the path data, arriving from a valid path. - filter_context()->SetURL(GURL(url_string + path)); + SetupFilterContextWithGURL(GURL(url_string + path)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); size_t feed_block_size = 100; @@ -708,7 +730,7 @@ EXPECT_EQ(output, expanded_); // Test decode the path data, arriving from a invalid path. - filter_context()->SetURL(GURL(url_string)); + SetupFilterContextWithGURL(GURL(url_string)); filter.reset(Filter::Factory(filter_types, *filter_context())); feed_block_size = 100; @@ -753,7 +775,7 @@ filter_types.push_back(Filter::FILTER_TYPE_SDCH); // Test decode the port data, arriving from a valid port. - filter_context()->SetURL(GURL(url_string + ":" + port)); + SetupFilterContextWithGURL(GURL(url_string + ":" + port)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); size_t feed_block_size = 100; @@ -764,7 +786,7 @@ EXPECT_EQ(output, expanded_); // Test decode the port data, arriving from a valid (default) port. - filter_context()->SetURL(GURL(url_string)); // Default port. + SetupFilterContextWithGURL(GURL(url_string)); // Default port. filter.reset(Filter::Factory(filter_types, *filter_context())); feed_block_size = 100; @@ -775,7 +797,7 @@ EXPECT_EQ(output, expanded_); // Test decode the port data, arriving from a invalid port. - filter_context()->SetURL(GURL(url_string + ":" + port + "1")); + SetupFilterContextWithGURL(GURL(url_string + ":" + port + "1")); filter.reset(Filter::Factory(filter_types, *filter_context())); feed_block_size = 100; @@ -856,8 +878,8 @@ }; // Test that filters can be cascaded (chained) so that the output of one filter -// is processed by the next one. This is most critical for SDCH, which is -// routinely followed by gzip (during encoding). The filter we'll test for will +// is processed by the next one. This is most critical for SDCH, which is +// routinely followed by gzip (during encoding). The filter we'll test for will // do the gzip decoding first, and then decode the SDCH content. TEST_F(SdchFilterTest, FilterChaining) { // Construct a valid SDCH dictionary from a VCDIFF dictionary. @@ -884,7 +906,7 @@ CHECK_GT(kLargeInputBufferSize, gzip_compressed_sdch.size()); CHECK_GT(kLargeInputBufferSize, sdch_compressed.size()); CHECK_GT(kLargeInputBufferSize, expanded_.size()); - filter_context()->SetURL(url); + SetupFilterContextWithGURL(url); scoped_ptr<Filter> filter( SdchFilterChainingTest::Factory(filter_types, *filter_context(), kLargeInputBufferSize)); @@ -962,16 +984,15 @@ filter_types.push_back(Filter::FILTER_TYPE_SDCH); filter_context()->SetMimeType("anything/mime"); - filter_context()->SetSdchResponse(true); + SetupFilterContextWithGURL(url); + Filter::FixupEncodingTypes(*filter_context(), &filter_types); ASSERT_EQ(filter_types.size(), 2u); EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH); EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH); // First try with a large buffer (larger than test input, or compressed data). - filter_context()->SetURL(url); - scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); - + scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); // Verify that chained filter is waiting for data. char tiny_output_buffer[10]; @@ -1020,7 +1041,7 @@ filter_types.push_back(Filter::FILTER_TYPE_GZIP); filter_context()->SetMimeType("anything/mime"); - filter_context()->SetSdchResponse(true); + SetupFilterContextWithGURL(url); Filter::FixupEncodingTypes(*filter_context(), &filter_types); ASSERT_EQ(filter_types.size(), 3u); EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE); @@ -1028,10 +1049,8 @@ EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP); // First try with a large buffer (larger than test input, or compressed data). - filter_context()->SetURL(url); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); - // Verify that chained filter is waiting for data. char tiny_output_buffer[10]; int tiny_output_size = sizeof(tiny_output_buffer); @@ -1077,17 +1096,15 @@ std::vector<Filter::FilterType> filter_types; filter_context()->SetMimeType("anything/mime"); - filter_context()->SetSdchResponse(true); + SetupFilterContextWithGURL(url); Filter::FixupEncodingTypes(*filter_context(), &filter_types); ASSERT_EQ(filter_types.size(), 2u); EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE); EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH); // First try with a large buffer (larger than test input, or compressed data). - filter_context()->SetURL(url); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); - // Verify that chained filter is waiting for data. char tiny_output_buffer[10]; int tiny_output_size = sizeof(tiny_output_buffer); @@ -1138,7 +1155,7 @@ filter_types.push_back(Filter::FILTER_TYPE_GZIP); filter_context()->SetMimeType("anything/mime"); - filter_context()->SetSdchResponse(true); + SetupFilterContextWithGURL(url); Filter::FixupEncodingTypes(*filter_context(), &filter_types); ASSERT_EQ(filter_types.size(), 3u); EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE); @@ -1146,7 +1163,6 @@ EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP); // First try with a large buffer (larger than test input, or compressed data). - filter_context()->SetURL(url); scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); // Verify that chained filter is waiting for data. @@ -1173,4 +1189,58 @@ EXPECT_EQ(output, expanded_); } +// Test to make sure we decode properly with an unexpected dictionary. +TEST_F(SdchFilterTest, UnexpectedDictionary) { + // Setup a dictionary, add it to the filter context, and create a filter + // based on that dictionary. + const std::string kSampleDomain = "sdchtest.com"; + std::string dictionary(NewSdchDictionary(kSampleDomain)); + std::string url_string = "http://" + kSampleDomain; + GURL url(url_string); + EXPECT_TRUE(AddSdchDictionary(dictionary, url)); + + SetupFilterContextWithGURL(url); + + std::vector<Filter::FilterType> filter_types; + filter_types.push_back(Filter::FILTER_TYPE_SDCH); + scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); + + // Setup another dictionary, expired. Don't add it to the filter context. + // Delete stored dictionaries first to handle platforms which only + // have room for a single dictionary. + sdch_manager_->ClearData(); + std::string expired_dictionary(NewSdchExpiredDictionary(kSampleDomain)); + + // Don't use the Helper function since its insertion check is indeterminate + // for a Max-Age: 0 dictionary. + sdch_manager_->AddSdchDictionary(expired_dictionary, url); + + std::string client_hash; + std::string server_hash; + SdchManager::GenerateHash(expired_dictionary, &client_hash, &server_hash); + + // Make sure Max-Age: 0 shows up as expired. + scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock); + clock->SetNow(base::Time::Now()); + clock->Advance(base::TimeDelta::FromMinutes(5)); + SdchProblemCode problem_code; + scoped_ptr<SdchManager::DictionarySet> hash_set( + sdch_manager_->GetDictionarySetByHash( + url, server_hash, &problem_code).Pass()); + ASSERT_TRUE(hash_set); + ASSERT_EQ(SDCH_OK, problem_code); + + const_cast<SdchManager::Dictionary*>( + hash_set->GetDictionary(server_hash))->SetClockForTesting( + clock.Pass()); + + // Encode output with the second dictionary. + std::string sdch_compressed(NewSdchCompressedData(expired_dictionary)); + + // See if the filter decodes it. + std::string output; + EXPECT_TRUE(FilterTestData(sdch_compressed, 100, 100, filter.get(), &output)); + EXPECT_EQ(expanded_, output); +} + } // namespace net
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc index 4cbde27..74bd6bf 100644 --- a/net/ftp/ftp_network_transaction.cc +++ b/net/ftp/ftp_network_transaction.cc
@@ -965,14 +965,16 @@ switch (GetErrorClass(response.status_code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_INVALID_RESPONSE); - case ERROR_CLASS_OK: - if (!ExtractPortFromEPSVResponse( response, &data_connection_port_)) + case ERROR_CLASS_OK: { + int port; + if (!ExtractPortFromEPSVResponse(response, &port)) return Stop(ERR_INVALID_RESPONSE); - if (data_connection_port_ < 1024 || - !IsPortAllowedByFtp(data_connection_port_)) + if (port < 1024 || !IsPortAllowedByFtp(port)) return Stop(ERR_UNSAFE_PORT); + data_connection_port_ = static_cast<uint16>(port); next_state_ = STATE_DATA_CONNECT; break; + } case ERROR_CLASS_INFO_NEEDED: return Stop(ERR_INVALID_RESPONSE); case ERROR_CLASS_TRANSIENT_ERROR: @@ -999,14 +1001,16 @@ switch (GetErrorClass(response.status_code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_INVALID_RESPONSE); - case ERROR_CLASS_OK: - if (!ExtractPortFromPASVResponse(response, &data_connection_port_)) + case ERROR_CLASS_OK: { + int port; + if (!ExtractPortFromPASVResponse(response, &port)) return Stop(ERR_INVALID_RESPONSE); - if (data_connection_port_ < 1024 || - !IsPortAllowedByFtp(data_connection_port_)) + if (port < 1024 || !IsPortAllowedByFtp(port)) return Stop(ERR_UNSAFE_PORT); + data_connection_port_ = static_cast<uint16>(port); next_state_ = STATE_DATA_CONNECT; break; + } case ERROR_CLASS_INFO_NEEDED: return Stop(ERR_INVALID_RESPONSE); case ERROR_CLASS_TRANSIENT_ERROR:
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h index c8ed550..e350e16 100644 --- a/net/ftp/ftp_network_transaction.h +++ b/net/ftp/ftp_network_transaction.h
@@ -8,6 +8,7 @@ #include <string> #include <utility> +#include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -245,7 +246,7 @@ // with any trailing slash removed. std::string current_remote_directory_; - int data_connection_port_; + uint16 data_connection_port_; ClientSocketFactory* socket_factory_;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 20ffdd1..8cddaf5 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -1027,11 +1027,8 @@ return OK; } - HostPortPair endpoint = HostPortPair(request_->url.HostNoBrackets(), - request_->url.EffectiveIntPort()); - ProcessAlternateProtocol(session_, - *response_.headers.get(), - endpoint); + ProcessAlternateProtocol(session_, *response_.headers.get(), + HostPortPair::FromURL(request_->url)); int rv = HandleAuthChallenge(); if (rv != OK)
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index d08d162..878406e 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -268,12 +268,15 @@ base::MessageLoop::current()->RunUntilIdle(); } + const char* GetAlternateProtocolFromParam() { + return + AlternateProtocolToString(AlternateProtocolFromNextProto(GetParam())); + } + // This is the expected return from a current server advertising SPDY. std::string GetAlternateProtocolHttpHeader() { - return - std::string("Alternate-Protocol: 443:") + - AlternateProtocolToString(AlternateProtocolFromNextProto(GetParam())) + - "\r\n\r\n"; + return std::string("Alternate-Protocol: 443:") + + GetAlternateProtocolFromParam() + "\r\n\r\n"; } // Either |write_failure| specifies a write failure or |read_failure| @@ -407,8 +410,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, HttpNetworkTransactionTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); namespace { @@ -10107,10 +10109,12 @@ }; MockRead data_reads_1[] = { MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), - MockRead("HTTP/1.1 200 OK\r\n" - "Alternate-Protocol: 443:npn-spdy/2\r\n" - "Proxy-Connection: close\r\n" - "\r\n"), + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Alternate-Protocol: 443:"), + MockRead(GetAlternateProtocolFromParam()), + MockRead("\r\n"), + MockRead("Proxy-Connection: close\r\n"), + MockRead("\r\n"), }; StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1), data_writes_1, arraysize(data_writes_1)); @@ -11402,8 +11406,7 @@ // SPDY GET for HTTP URL (through the proxy, but not the tunnel). SpdyHeaderBlock req2_block; req2_block[spdy_util_.GetMethodKey()] = "GET"; - req2_block[spdy_util_.GetPathKey()] = - spdy_util_.is_spdy2() ? http_url.c_str() : "/"; + req2_block[spdy_util_.GetPathKey()] = "/"; req2_block[spdy_util_.GetHostKey()] = "www.google.com:443"; req2_block[spdy_util_.GetSchemeKey()] = "http"; spdy_util_.MaybeAddVersionHeader(&req2_block);
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 694d394..bdaf57f 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -42,7 +42,7 @@ struct HttpProxyClientSocketPoolTestParams { HttpProxyClientSocketPoolTestParams() : proxy_type(HTTP), - protocol(kProtoSPDY3) {} + protocol(kProtoSPDY31) {} HttpProxyClientSocketPoolTestParams( HttpProxyType proxy_type, @@ -342,12 +342,6 @@ HttpProxyClientSocketPoolTests, HttpProxyClientSocketPoolTest, ::testing::Values( - HttpProxyClientSocketPoolTestParams(HTTP, kProtoDeprecatedSPDY2), - HttpProxyClientSocketPoolTestParams(HTTPS, kProtoDeprecatedSPDY2), - HttpProxyClientSocketPoolTestParams(SPDY, kProtoDeprecatedSPDY2), - HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY3), - HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY3), - HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY3), HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31), HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31), HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc index 65ecd11..1bf541b 100644 --- a/net/http/http_server_properties_impl.cc +++ b/net/http/http_server_properties_impl.cc
@@ -67,7 +67,7 @@ } // Attempt to find canonical servers. - int canonical_ports[] = { 80, 443 }; + uint16 canonical_ports[] = { 80, 443 }; for (size_t i = 0; i < canonical_suffixes_.size(); ++i) { std::string canonical_suffix = canonical_suffixes_[i]; for (size_t j = 0; j < arraysize(canonical_ports); ++j) { @@ -301,8 +301,14 @@ const HostPortPair& server) { AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server); if (it == alternate_protocol_map_.end()) { - LOG(DFATAL) << "Trying to mark unknown alternate protocol broken."; - return; + if (!HasAlternateProtocol(server)) { + LOG(DFATAL) << "Trying to mark unknown alternate protocol broken."; + return; + } + // This server's alternate protocol information is coming from a canonical + // server. Add an entry in the map for this server explicitly so that + // it can be marked as broken. + it = alternate_protocol_map_.Put(server, GetAlternateProtocol(server)); } it->second.is_broken = true; int count = ++broken_alternate_protocol_map_[server];
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc index 1c016b7..3d1bacb 100644 --- a/net/http/http_server_properties_impl_unittest.cc +++ b/net/http/http_server_properties_impl_unittest.cc
@@ -475,6 +475,23 @@ EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair)); } +TEST_F(AlternateProtocolServerPropertiesTest, CanonicalBroken2) { + HostPortPair test_host_port_pair("foo.c.youtube.com", 80); + HostPortPair canonical_port_pair("bar.c.youtube.com", 80); + + AlternateProtocolInfo canonical_protocol(1234, QUIC, 1); + + impl_.SetAlternateProtocol(canonical_port_pair, + canonical_protocol.port, + canonical_protocol.protocol, + canonical_protocol.probability); + + impl_.SetBrokenAlternateProtocol(test_host_port_pair); + AlternateProtocolInfo alternate = + impl_.GetAlternateProtocol(test_host_port_pair); + EXPECT_TRUE(alternate.is_broken); +} + TEST_F(AlternateProtocolServerPropertiesTest, ClearWithCanonical) { HostPortPair test_host_port_pair("foo.c.youtube.com", 80); HostPortPair canonical_port_pair("bar.c.youtube.com", 80);
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc index 41b70b1..5773129 100644 --- a/net/http/http_server_properties_manager.cc +++ b/net/http/http_server_properties_manager.cc
@@ -449,9 +449,8 @@ continue; } - net::AlternateProtocolInfo port_alternate_protocol(port, - protocol, - probability); + net::AlternateProtocolInfo port_alternate_protocol( + static_cast<uint16>(port), protocol, probability); alternate_protocol_map->Put(server, port_alternate_protocol); ++count; } while (false);
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc index 29d9b26..f84b80c 100644 --- a/net/http/http_stream_factory.cc +++ b/net/http/http_stream_factory.cc
@@ -60,7 +60,7 @@ } if (!base::StringToInt(port_protocol_vector[0], &port) || - port <= 0 || port >= 1 << 16) { + port == 0 || !IsPortValid(port)) { DVLOG(1) << kAlternateProtocolHeader << " header has unrecognizable port: " << port_protocol_vector[0]; @@ -94,8 +94,8 @@ return; } - http_server_properties->SetAlternateProtocol(host_port, port, protocol, - probability); + http_server_properties->SetAlternateProtocol( + host_port, static_cast<uint16>(port), protocol, probability); } GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url,
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index 8304694..8b12dba 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc
@@ -184,8 +184,7 @@ if (original_url.SchemeIs("ftp")) return kNoAlternateProtocol; - HostPortPair origin = HostPortPair(original_url.HostNoBrackets(), - original_url.EffectiveIntPort()); + HostPortPair origin = HostPortPair::FromURL(original_url); HttpServerProperties& http_server_properties = *session_->http_server_properties();
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index a11dd2e..8369443 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc
@@ -132,13 +132,10 @@ int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) { DCHECK_GT(num_streams, 0); - HostPortPair origin_server = - HostPortPair(request_info_.url.HostNoBrackets(), - request_info_.url.EffectiveIntPort()); base::WeakPtr<HttpServerProperties> http_server_properties = session_->http_server_properties(); - if (http_server_properties && - http_server_properties->SupportsSpdy(origin_server)) { + if (http_server_properties && http_server_properties->SupportsSpdy( + HostPortPair::FromURL(request_info_.url))) { num_streams_ = 1; } else { num_streams_ = num_streams; @@ -617,8 +614,7 @@ } int HttpStreamFactoryImpl::Job::DoStart() { - int port = request_info_.url.EffectiveIntPort(); - origin_ = HostPortPair(request_info_.url.HostNoBrackets(), port); + origin_ = HostPortPair::FromURL(request_info_.url); origin_url_ = stream_factory_->ApplyHostMappingRules( request_info_.url, &origin_); @@ -628,14 +624,14 @@ priority_)); // Don't connect to restricted ports. - bool is_port_allowed = IsPortAllowedByDefault(port); + bool is_port_allowed = IsPortAllowedByDefault(origin_.port()); if (request_info_.url.SchemeIs("ftp")) { // Never share connection with other jobs for FTP requests. DCHECK(!waiting_job_); - is_port_allowed = IsPortAllowedByFtp(port); + is_port_allowed = IsPortAllowedByFtp(origin_.port()); } - if (!is_port_allowed && !IsPortAllowedByOverride(port)) { + if (!is_port_allowed && !IsPortAllowedByOverride(origin_.port())) { if (waiting_job_) { waiting_job_->Resume(this); waiting_job_ = NULL;
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc index 587358d..32900f9 100644 --- a/net/http/http_stream_factory_impl_request_unittest.cc +++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -19,8 +19,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, HttpStreamFactoryImplRequestTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); namespace {
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc index 68e9114..4ac5467 100644 --- a/net/http/http_stream_factory_impl_unittest.cc +++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -424,8 +424,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, HttpStreamFactoryTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); TEST_P(HttpStreamFactoryTest, PreconnectDirect) { for (size_t i = 0; i < arraysize(kTests); ++i) {
diff --git a/net/net.gyp b/net/net.gyp index 3c9a520..da91a92 100644 --- a/net/net.gyp +++ b/net/net.gyp
@@ -876,8 +876,12 @@ '../testing/gmock.gyp:gmock', ], 'sources': [ + 'base/captured_net_log_entry.cc', + 'base/captured_net_log_entry.h', 'base/capturing_net_log.cc', 'base/capturing_net_log.h', + 'base/capturing_net_log_observer.cc', + 'base/capturing_net_log_observer.h', 'base/load_timing_info_test_util.cc', 'base/load_timing_info_test_util.h', 'base/mock_file_stream.cc',
diff --git a/net/net.gypi b/net/net.gypi index 337f016..cc9ff35 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -1236,8 +1236,8 @@ 'websockets/websocket_frame_parser.h', 'websockets/websocket_handshake_constants.cc', 'websockets/websocket_handshake_constants.h', - 'websockets/websocket_handshake_handler.cc', - 'websockets/websocket_handshake_handler.h', + 'websockets/websocket_handshake_challenge.cc', + 'websockets/websocket_handshake_challenge.h', 'websockets/websocket_handshake_request_info.cc', 'websockets/websocket_handshake_request_info.h', 'websockets/websocket_handshake_response_info.cc', @@ -1709,7 +1709,7 @@ 'websockets/websocket_extension_parser_test.cc', 'websockets/websocket_frame_parser_test.cc', 'websockets/websocket_frame_test.cc', - 'websockets/websocket_handshake_handler_test.cc', + 'websockets/websocket_handshake_challenge_test.cc', 'websockets/websocket_handshake_stream_create_helper_test.cc', 'websockets/websocket_inflater_test.cc', 'websockets/websocket_stream_test.cc',
diff --git a/net/proxy/network_delegate_error_observer_unittest.cc b/net/proxy/network_delegate_error_observer_unittest.cc index 5d2c501..da87f8d 100644 --- a/net/proxy/network_delegate_error_observer_unittest.cc +++ b/net/proxy/network_delegate_error_observer_unittest.cc
@@ -77,10 +77,6 @@ bool OnCanThrottleRequest(const URLRequest& request) const override { return false; } - int OnBeforeSocketStreamConnect(SocketStream* stream, - const CompletionCallback& callback) override { - return OK; - } bool got_pac_error_; };
diff --git a/net/proxy/proxy_config_service_android.cc b/net/proxy/proxy_config_service_android.cc index f1a0b6c..50407fe 100644 --- a/net/proxy/proxy_config_service_android.cc +++ b/net/proxy/proxy_config_service_android.cc
@@ -197,7 +197,8 @@ : jni_delegate_(this), network_task_runner_(network_task_runner), jni_task_runner_(jni_task_runner), - get_property_callback_(get_property_callback) { + get_property_callback_(get_property_callback), + exclude_pac_url_(false) { } void SetupJNI() { @@ -271,13 +272,22 @@ const std::vector<std::string>& exclusion_list) { DCHECK(OnJNIThread()); ProxyConfig proxy_config; - CreateStaticProxyConfig(host, port, pac_url, exclusion_list, &proxy_config); + if (exclude_pac_url_) { + CreateStaticProxyConfig(host, port, "", exclusion_list, &proxy_config); + } else { + CreateStaticProxyConfig(host, port, pac_url, exclusion_list, + &proxy_config); + } network_task_runner_->PostTask( FROM_HERE, base::Bind( &Delegate::SetNewConfigOnNetworkThread, this, proxy_config)); } + void set_exclude_pac_url(bool enabled) { + exclude_pac_url_ = enabled; + } + private: friend class base::RefCountedThreadSafe<Delegate>; @@ -344,6 +354,7 @@ scoped_refptr<base::SequencedTaskRunner> jni_task_runner_; GetPropertyCallback get_property_callback_; ProxyConfig proxy_config_; + bool exclude_pac_url_; DISALLOW_COPY_AND_ASSIGN(Delegate); }; @@ -366,6 +377,10 @@ return RegisterNativesImpl(env); } +void ProxyConfigServiceAndroid::set_exclude_pac_url(bool enabled) { + delegate_->set_exclude_pac_url(enabled); +} + void ProxyConfigServiceAndroid::AddObserver(Observer* observer) { delegate_->AddObserver(observer); }
diff --git a/net/proxy/proxy_config_service_android.h b/net/proxy/proxy_config_service_android.h index d642d37..cb15bc5 100644 --- a/net/proxy/proxy_config_service_android.h +++ b/net/proxy/proxy_config_service_android.h
@@ -64,6 +64,11 @@ // Register JNI bindings. static bool Register(JNIEnv* env); + // Android provides a local HTTP proxy that does PAC resolution. When this + // setting is enabled, the proxy config service ignores the PAC URL and uses + // the local proxy for all proxy resolution. + void set_exclude_pac_url(bool enabled); + // ProxyConfigService: // Called only on the network thread. virtual void AddObserver(Observer* observer) override;
diff --git a/net/proxy/proxy_resolver_v8.cc b/net/proxy/proxy_resolver_v8.cc index 24fbe9e..963153d 100644 --- a/net/proxy/proxy_resolver_v8.cc +++ b/net/proxy/proxy_resolver_v8.cc
@@ -196,7 +196,7 @@ return false; v8::HandleScope scope(isolate); - v8::Local<v8::String> str_object = object->ToString(); + v8::Local<v8::String> str_object = object->ToString(isolate); if (str_object.IsEmpty()) return false; *utf16_result = V8StringToUTF16(str_object); @@ -211,7 +211,8 @@ if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) return false; - const base::string16 hostname_utf16 = V8StringToUTF16(args[0]->ToString()); + const base::string16 hostname_utf16 = + V8StringToUTF16(v8::Local<v8::String>::Cast(args[0])); // If the hostname is already in ASCII, simply return it as is. if (base::IsStringASCII(hostname_utf16)) { @@ -393,7 +394,7 @@ return ERR_PAC_SCRIPT_FAILED; } - base::string16 ret_str = V8StringToUTF16(ret->ToString()); + base::string16 ret_str = V8StringToUTF16(v8::Local<v8::String>::Cast(ret)); if (!base::IsStringASCII(ret_str)) { // TODO(eroman): Rather than failing when a wide string is returned, we @@ -656,7 +657,8 @@ return; } - std::string ip_address_list = V8StringToUTF8(args[0]->ToString()); + std::string ip_address_list = + V8StringToUTF8(v8::Local<v8::String>::Cast(args[0])); if (!base::IsStringASCII(ip_address_list)) { args.GetReturnValue().SetNull(); return; @@ -681,12 +683,14 @@ return; } - std::string ip_address = V8StringToUTF8(args[0]->ToString()); + std::string ip_address = + V8StringToUTF8(v8::Local<v8::String>::Cast(args[0])); if (!base::IsStringASCII(ip_address)) { args.GetReturnValue().Set(false); return; } - std::string ip_prefix = V8StringToUTF8(args[1]->ToString()); + std::string ip_prefix = + V8StringToUTF8(v8::Local<v8::String>::Cast(args[1])); if (!base::IsStringASCII(ip_prefix)) { args.GetReturnValue().Set(false); return;
diff --git a/net/proxy/proxy_script_fetcher_impl_unittest.cc b/net/proxy/proxy_script_fetcher_impl_unittest.cc index 2073d00..4c5bd4c 100644 --- a/net/proxy/proxy_script_fetcher_impl_unittest.cc +++ b/net/proxy/proxy_script_fetcher_impl_unittest.cc
@@ -179,11 +179,6 @@ return false; } - int OnBeforeSocketStreamConnect(SocketStream* stream, - const CompletionCallback& callback) override { - return OK; - } - DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate); };
diff --git a/net/proxy/proxy_server.cc b/net/proxy/proxy_server.cc index 0b9ba67..78d5c3e 100644 --- a/net/proxy/proxy_server.cc +++ b/net/proxy/proxy_server.cc
@@ -6,6 +6,7 @@ #include <algorithm> +#include "base/basictypes.h" #include "base/strings/string_util.h" #include "net/base/net_util.h" #include "net/http/http_util.h" @@ -238,7 +239,7 @@ if (port == -1) port = GetDefaultPortForScheme(scheme); - host_port_pair = HostPortPair(host, port); + host_port_pair = HostPortPair(host, static_cast<uint16>(port)); } return ProxyServer(scheme, host_port_pair);
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc index 8073c5b..7e9f81a 100644 --- a/net/quic/congestion_control/pacing_sender.cc +++ b/net/quic/congestion_control/pacing_sender.cc
@@ -27,6 +27,11 @@ sender_->SetFromConfig(config, is_server, using_pacing); } +void PacingSender::ResumeConnectionState( + const CachedNetworkParameters& cached_network_params) { + sender_->ResumeConnectionState(cached_network_params); +} + void PacingSender::SetNumEmulatedConnections(int num_connections) { sender_->SetNumEmulatedConnections(num_connections); }
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h index 4eb3dab..d7d3b2d 100644 --- a/net/quic/congestion_control/pacing_sender.h +++ b/net/quic/congestion_control/pacing_sender.h
@@ -16,6 +16,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "net/quic/congestion_control/send_algorithm_interface.h" +#include "net/quic/crypto/cached_network_parameters.h" #include "net/quic/quic_bandwidth.h" #include "net/quic/quic_config.h" #include "net/quic/quic_protocol.h" @@ -38,6 +39,8 @@ void SetFromConfig(const QuicConfig& config, bool is_server, bool using_pacing) override; + void ResumeConnectionState( + const CachedNetworkParameters& cached_network_params) override; void SetNumEmulatedConnections(int num_connections) override; void OnCongestionEvent(bool rtt_updated, QuicByteCount bytes_in_flight, @@ -63,6 +66,7 @@ bool InRecovery() const override; QuicByteCount GetSlowStartThreshold() const override; CongestionControlType GetCongestionControlType() const override; + // End implementation of SendAlgorithmInterface. private: scoped_ptr<SendAlgorithmInterface> sender_; // Underlying sender.
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index 7195f81..322ff1d 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -12,6 +12,7 @@ #include "base/basictypes.h" #include "net/base/net_export.h" +#include "net/quic/crypto/cached_network_parameters.h" #include "net/quic/quic_bandwidth.h" #include "net/quic/quic_clock.h" #include "net/quic/quic_config.h" @@ -113,6 +114,10 @@ virtual QuicByteCount GetSlowStartThreshold() const = 0; virtual CongestionControlType GetCongestionControlType() const = 0; + + // Called by the Session when we get a bandwidth estimate from the client. + virtual void ResumeConnectionState( + const CachedNetworkParameters& cached_network_params) = 0; }; } // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 2d0efd7..5fa1559 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -27,13 +27,12 @@ const uint32 kDefaultNumConnections = 2; // N-connection emulation. } // namespace -TcpCubicSender::TcpCubicSender( - const QuicClock* clock, - const RttStats* rtt_stats, - bool reno, - QuicPacketCount initial_tcp_congestion_window, - QuicPacketCount max_tcp_congestion_window, - QuicConnectionStats* stats) +TcpCubicSender::TcpCubicSender(const QuicClock* clock, + const RttStats* rtt_stats, + bool reno, + QuicPacketCount initial_tcp_congestion_window, + QuicPacketCount max_tcp_congestion_window, + QuicConnectionStats* stats) : hybrid_slow_start_(clock), cubic_(clock, stats), rtt_stats_(rtt_stats), @@ -49,8 +48,8 @@ slowstart_threshold_(max_tcp_congestion_window), previous_slowstart_threshold_(0), last_cutback_exited_slowstart_(false), - max_tcp_congestion_window_(max_tcp_congestion_window) { -} + max_tcp_congestion_window_(max_tcp_congestion_window), + clock_(clock) {} TcpCubicSender::~TcpCubicSender() { UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); @@ -73,6 +72,26 @@ } } +void TcpCubicSender::ResumeConnectionState( + const CachedNetworkParameters& cached_network_params) { + // If the previous bandwidth estimate is less than an hour old, store in + // preparation for doing bandwidth resumption. + int64 seconds_since_estimate = + clock_->WallNow().ToUNIXSeconds() - cached_network_params.timestamp(); + if (seconds_since_estimate > kNumSecondsPerHour) { + return; + } + + QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( + cached_network_params.bandwidth_estimate_bytes_per_second()); + QuicTime::Delta rtt_ms = + QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); + congestion_window_ = bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize; + + // TODO(rjshade): Set appropriate CWND when previous connection was in slow + // start at time of estimate. +} + void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { num_connections_ = max(1, num_connections); cubic_.SetNumConnections(num_connections_);
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index a7507a2..eeb9331 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -15,6 +15,7 @@ #include "net/quic/congestion_control/hybrid_slow_start.h" #include "net/quic/congestion_control/prr_sender.h" #include "net/quic/congestion_control/send_algorithm_interface.h" +#include "net/quic/crypto/cached_network_parameters.h" #include "net/quic/quic_bandwidth.h" #include "net/quic/quic_connection_stats.h" #include "net/quic/quic_protocol.h" @@ -43,6 +44,8 @@ void SetFromConfig(const QuicConfig& config, bool is_server, bool using_pacing) override; + void ResumeConnectionState( + const CachedNetworkParameters& cached_network_params) override; void SetNumEmulatedConnections(int num_connections) override; void OnCongestionEvent(bool rtt_updated, QuicByteCount bytes_in_flight, @@ -130,6 +133,8 @@ // Maximum number of outstanding packets for tcp. QuicPacketCount max_tcp_congestion_window_; + const QuicClock* clock_; + DISALLOW_COPY_AND_ASSIGN(TcpCubicSender); };
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index 427dd8c..e4737eb 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -701,5 +701,32 @@ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); } +TEST_F(TcpCubicSenderTest, BandwidthResumption) { + // Test that when provided with CachedNetworkParameters and opted in to the + // bandwidth resumption experiment, that the TcpCubicSender sets initial CWND + // appropriately. + + // Set some common values. + CachedNetworkParameters cached_network_params; + const QuicPacketCount kNumberOfPackets = 123; + const int kBandwidthEstimateBytesPerSecond = + kNumberOfPackets * kMaxPacketSize; + cached_network_params.set_bandwidth_estimate_bytes_per_second( + kBandwidthEstimateBytesPerSecond); + cached_network_params.set_min_rtt_ms(1000); + + // Ensure that an old estimate is not used for bandwidth resumption. + cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() - + (kNumSecondsPerHour + 1)); + sender_->ResumeConnectionState(cached_network_params); + EXPECT_EQ(10u, sender_->congestion_window()); + + // If the estimate is new enough, make sure it is used. + cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() - + (kNumSecondsPerHour - 1)); + sender_->ResumeConnectionState(cached_network_params); + EXPECT_EQ(kNumberOfPackets, sender_->congestion_window()); +} + } // namespace test } // namespace net
diff --git a/net/quic/congestion_control/tcp_loss_algorithm.cc b/net/quic/congestion_control/tcp_loss_algorithm.cc index 6cf56d8..9366105 100644 --- a/net/quic/congestion_control/tcp_loss_algorithm.cc +++ b/net/quic/congestion_control/tcp_loss_algorithm.cc
@@ -40,7 +40,7 @@ continue; } - LOG_IF(DFATAL, it->nack_count == 0) + LOG_IF(DFATAL, it->nack_count == 0 && it->sent_time.IsInitialized()) << "All packets less than largest observed should have been nacked." << "sequence_number:" << sequence_number << " largest_observed:" << largest_observed;
diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc index 5819fb1..fe6a6ea 100644 --- a/net/quic/congestion_control/tcp_loss_algorithm_test.cc +++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -12,8 +12,14 @@ #include "net/quic/test_tools/mock_clock.h" #include "testing/gtest/include/gtest/gtest.h" +using std::vector; + namespace net { namespace test { +namespace { + +// Default packet length. +const uint32 kDefaultLength = 1000; class TcpLossAlgorithmTest : public ::testing::Test { protected: @@ -24,9 +30,16 @@ clock_.Now()); } + ~TcpLossAlgorithmTest() override { + STLDeleteElements(&packets_); + } + void SendDataPacket(QuicPacketSequenceNumber sequence_number) { + packets_.push_back(QuicPacket::NewDataPacket( + nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false, + PACKET_1BYTE_SEQUENCE_NUMBER)); SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, - nullptr, 0, new RetransmittableFrames()); + packets_.back(), 0, new RetransmittableFrames()); unacked_packets_.AddSentPacket(packet, 0, NOT_RETRANSMISSION, clock_.Now(), 1000, true); } @@ -43,6 +56,7 @@ } } + vector<QuicPacket*> packets_; QuicUnackedPacketMap unacked_packets_; TCPLossAlgorithm loss_algorithm_; RttStats rtt_stats_; @@ -179,5 +193,6 @@ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); } +} // namespace } // namespace test } // namespace net
diff --git a/net/quic/congestion_control/time_loss_algorithm.cc b/net/quic/congestion_control/time_loss_algorithm.cc index 9dd9ae9..b5f90b7 100644 --- a/net/quic/congestion_control/time_loss_algorithm.cc +++ b/net/quic/congestion_control/time_loss_algorithm.cc
@@ -46,8 +46,10 @@ if (!it->in_flight) { continue; } - LOG_IF(DFATAL, it->nack_count == 0) - << "All packets less than largest observed should have been nacked."; + LOG_IF(DFATAL, it->nack_count == 0 && it->sent_time.IsInitialized()) + << "All packets less than largest observed should have been nacked." + << "sequence_number:" << sequence_number + << " largest_observed:" << largest_observed; // Packets are sent in order, so break when we haven't waited long enough // to lose any more packets and leave the loss_time_ set for the timeout.
diff --git a/net/quic/congestion_control/time_loss_algorithm_test.cc b/net/quic/congestion_control/time_loss_algorithm_test.cc index b964d28..1e9b7e5 100644 --- a/net/quic/congestion_control/time_loss_algorithm_test.cc +++ b/net/quic/congestion_control/time_loss_algorithm_test.cc
@@ -12,8 +12,14 @@ #include "net/quic/test_tools/mock_clock.h" #include "testing/gtest/include/gtest/gtest.h" +using std::vector; + namespace net { namespace test { +namespace { + +// Default packet length. +const uint32 kDefaultLength = 1000; class TimeLossAlgorithmTest : public ::testing::Test { protected: @@ -24,9 +30,16 @@ clock_.Now()); } + ~TimeLossAlgorithmTest() override { + STLDeleteElements(&packets_); + } + void SendDataPacket(QuicPacketSequenceNumber sequence_number) { + packets_.push_back(QuicPacket::NewDataPacket( + nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false, + PACKET_1BYTE_SEQUENCE_NUMBER)); SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, - nullptr, 0, new RetransmittableFrames()); + packets_.back(), 0, new RetransmittableFrames()); unacked_packets_.AddSentPacket(packet, 0, NOT_RETRANSMISSION, clock_.Now(), 1000, true); } @@ -43,6 +56,7 @@ } } + vector<QuicPacket*> packets_; QuicUnackedPacketMap unacked_packets_; TimeLossAlgorithm loss_algorithm_; RttStats rtt_stats_; @@ -134,5 +148,6 @@ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); } +} // namespace } // namespace test } // namespace net
diff --git a/net/quic/crypto/common_cert_set.cc b/net/quic/crypto/common_cert_set.cc index 09379f3..b2ea3a7 100644 --- a/net/quic/crypto/common_cert_set.cc +++ b/net/quic/crypto/common_cert_set.cc
@@ -153,7 +153,7 @@ private: CommonCertSetsQUIC() {} - virtual ~CommonCertSetsQUIC() {} + ~CommonCertSetsQUIC() override {} friend struct DefaultSingletonTraits<CommonCertSetsQUIC>; DISALLOW_COPY_AND_ASSIGN(CommonCertSetsQUIC);
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc index 9125968..23e8ea2 100644 --- a/net/quic/crypto/crypto_handshake_message.cc +++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -302,8 +302,9 @@ static_cast<int>(it->second.size())); done = true; break; + case kSNI: case kUAID: - ret += it->second; + ret += "\"" + it->second + "\""; done = true; break; }
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index d010776..57a5508 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h
@@ -71,6 +71,9 @@ // FEC options const QuicTag kFHDR = TAG('F', 'H', 'D', 'R'); // FEC protect headers +// Enable bandwidth resumption experiment. +const QuicTag kBWRE = TAG('B', 'W', 'R', 'E'); // Bandwidth resumption. + // Proof types (i.e. certificate types) // NOTE: although it would be silly to do so, specifying both kX509 and kX59R // is allowed and is equivalent to specifying only kX509.
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc index 274099c..97d6c3b 100644 --- a/net/quic/quic_client_session.cc +++ b/net/quic/quic_client_session.cc
@@ -13,6 +13,7 @@ #include "base/values.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" +#include "net/base/network_activity_monitor.h" #include "net/http/transport_security_state.h" #include "net/quic/crypto/proof_verifier_chromium.h" #include "net/quic/crypto/quic_server_info.h" @@ -633,6 +634,18 @@ "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount", connection()->sent_packet_manager().consecutive_tlp_count()); } + if (connection()->sent_packet_manager().HasUnackedPackets()) { + UMA_HISTOGRAM_TIMES( + "Net.QuicSession.LocallyTimedOutWithOpenStreams." + "TimeSinceLastReceived.UnackedPackets", + NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived()); + } else { + UMA_HISTOGRAM_TIMES( + "Net.QuicSession.LocallyTimedOutWithOpenStreams." + "TimeSinceLastReceived.NoUnackedPackets", + NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived()); + } + } else { UMA_HISTOGRAM_COUNTS( "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc index 66583b8..88beca7 100644 --- a/net/quic/quic_client_session_test.cc +++ b/net/quic/quic_client_session_test.cc
@@ -52,6 +52,8 @@ /*is_secure=*/false, PRIVACY_MODE_DISABLED), &crypto_config_, nullptr); + // Advance the time, because timers do not like uninitialized times. + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); } void TearDown() override { session_.CloseSessionOnError(ERR_ABORTED); }
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index fd9ec5f..62cbc64 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc
@@ -282,6 +282,11 @@ max_undecryptable_packets_ = config.max_undecryptable_packets(); } +void QuicConnection::ResumeConnectionState( + const CachedNetworkParameters& cached_network_params) { + sent_packet_manager_.ResumeConnectionState(cached_network_params); +} + void QuicConnection::SetNumOpenStreams(size_t num_streams) { sent_packet_manager_.SetNumOpenStreams(num_streams); } @@ -911,10 +916,6 @@ } else { // Send an ack much more quickly for crypto handshake packets. QuicTime::Delta delayed_ack_time = sent_packet_manager_.DelayedAckTime(); - if (last_stream_frames_.size() == 1 && - last_stream_frames_[0].stream_id == kCryptoStreamId) { - delayed_ack_time = QuicTime::Delta::Zero(); - } ack_alarm_->Set(clock_->ApproximateNow().Add(delayed_ack_time)); DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK."; } @@ -1449,6 +1450,13 @@ << QuicUtils::StringToHexASCIIDump( packet->serialized_packet.packet->AsStringPiece()); + QuicTime packet_send_time = QuicTime::Zero(); + if (FLAGS_quic_record_send_time_before_write) { + // Measure the RTT from before the write begins to avoid underestimating the + // min_rtt_, especially in cases where the thread blocks or gets swapped out + // during the WritePacket below. + packet_send_time = clock_->Now(); + } WriteResult result = writer_->WritePacket(encrypted->data(), encrypted->length(), self_address().address(), @@ -1467,7 +1475,16 @@ return false; } } - QuicTime now = clock_->Now(); + if (!FLAGS_quic_record_send_time_before_write) { + packet_send_time = clock_->Now(); + } + if (!packet_send_time.IsInitialized()) { + // TODO(jokulik): This is only needed because of the two code paths for + // initializing packet_send_time. Once "quic_record_send_time_before_write" + // is deprecated, this check can be removed. + LOG(DFATAL) << "The packet send time should never be zero. " + << "This is a programming bug, please report it."; + } if (result.status != WRITE_STATUS_ERROR && debug_visitor_.get() != nullptr) { // Pass the write result to the visitor. debug_visitor_->OnPacketSent(packet->serialized_packet, @@ -1475,14 +1492,17 @@ packet->encryption_level, packet->transmission_type, *encrypted, - now); + packet_send_time); } if (packet->transmission_type == NOT_RETRANSMISSION) { - time_of_last_sent_new_packet_ = now; + time_of_last_sent_new_packet_ = packet_send_time; } SetPingAlarm(); - DVLOG(1) << ENDPOINT << "time of last sent packet: " - << now.ToDebuggingValue(); + DVLOG(1) << ENDPOINT << "time " + << (FLAGS_quic_record_send_time_before_write ? + "we began writing " : "we finished writing ") + << "last sent packet: " + << packet_send_time.ToDebuggingValue(); // TODO(ianswett): Change the sequence number length and other packet creator // options by a more explicit API than setting a struct value directly, @@ -1494,7 +1514,7 @@ bool reset_retransmission_alarm = sent_packet_manager_.OnPacketSent( &packet->serialized_packet, packet->original_sequence_number, - now, + packet_send_time, encrypted->length(), packet->transmission_type, IsRetransmittable(*packet)); @@ -1585,6 +1605,12 @@ void QuicConnection::OnHandshakeComplete() { sent_packet_manager_.SetHandshakeConfirmed(); + // The client should immediately ack the SHLO to confirm the handshake is + // complete with the server. + if (!is_server_ && !ack_queued_) { + ack_alarm_->Cancel(); + ack_alarm_->Set(clock_->ApproximateNow()); + } } void QuicConnection::SendOrQueuePacket(QueuedPacket packet) { @@ -1598,8 +1624,6 @@ sent_entropy_manager_.RecordPacketEntropyHash( packet.serialized_packet.sequence_number, packet.serialized_packet.entropy_hash); - LOG_IF(DFATAL, !queued_packets_.empty() && !writer_->IsWriteBlocked()) - << "Packets should only be left queued if we're write blocked."; if (!WritePacket(&packet)) { queued_packets_.push_back(packet); }
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 96f5cbc..abab048 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h
@@ -24,6 +24,7 @@ #include <string> #include <vector> +#include "base/basictypes.h" #include "base/logging.h" #include "net/base/iovec.h" #include "net/base/ip_endpoint.h" @@ -258,6 +259,11 @@ // Sets connection parameters from the supplied |config|. void SetFromConfig(const QuicConfig& config); + // Called by the Session when the client has provided CachedNetworkParameters. + // Virtual for tests. + virtual void ResumeConnectionState( + const CachedNetworkParameters& cached_network_params); + // Sets the number of active streams on the connection for congestion control. void SetNumOpenStreams(size_t num_streams); @@ -689,7 +695,7 @@ IPEndPoint self_address_; IPEndPoint peer_address_; // Used to store latest peer port to possibly migrate to later. - int migrating_peer_port_; + uint16 migrating_peer_port_; // True if the last packet has gotten far enough in the framer to be // decrypted. @@ -783,8 +789,8 @@ // This is used for timeouts, and does not indicate the packet was processed. QuicTime time_of_last_received_packet_; - // The last time a new (non-retransmitted) packet was sent for this - // connection. + // The last time this connection began sending a new (non-retransmitted) + // packet. QuicTime time_of_last_sent_new_packet_; // Sequence number of the last sent packet. Packets are guaranteed to be sent
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 4e58dfd..ede61c8 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc
@@ -67,7 +67,7 @@ } bool GenerateCongestionFeedback( - QuicCongestionFeedbackFrame* congestion_feedback) { + QuicCongestionFeedbackFrame* congestion_feedback) override { if (feedback_ == nullptr) { return false; } @@ -95,6 +95,7 @@ // QuicEncrypter interface. bool SetKey(StringPiece key) override { return true; } + bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; } bool Encrypt(StringPiece nonce, @@ -149,6 +150,7 @@ // QuicDecrypter interface bool SetKey(StringPiece key) override { return true; } + bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; } bool Decrypt(StringPiece nonce, @@ -258,7 +260,7 @@ class TestPacketWriter : public QuicPacketWriter { public: - explicit TestPacketWriter(QuicVersion version) + TestPacketWriter(QuicVersion version, MockClock *clock) : version_(version), framer_(SupportedVersions(version_)), last_packet_size_(0), @@ -268,7 +270,9 @@ final_bytes_of_last_packet_(0), final_bytes_of_previous_packet_(0), use_tagging_decrypter_(false), - packets_write_attempts_(0) { + packets_write_attempts_(0), + clock_(clock), + write_pause_time_delta_(QuicTime::Delta::Zero()) { } // QuicPacketWriter interface @@ -297,6 +301,10 @@ return WriteResult(WRITE_STATUS_BLOCKED, -1); } last_packet_size_ = packet.length(); + + if (!write_pause_time_delta_.IsZero()) { + clock_->AdvanceTime(write_pause_time_delta_); + } return WriteResult(WRITE_STATUS_OK, last_packet_size_); } @@ -310,6 +318,11 @@ void BlockOnNextWrite() { block_on_next_write_ = true; } + // Sets the amount of time that the writer should before the actual write. + void SetWritePauseTimeDelta(QuicTime::Delta delta) { + write_pause_time_delta_ = delta; + } + const QuicPacketHeader& header() { return framer_.header(); } size_t frame_count() const { return framer_.num_frames(); } @@ -390,6 +403,10 @@ uint32 final_bytes_of_previous_packet_; bool use_tagging_decrypter_; uint32 packets_write_attempts_; + MockClock *clock_; + // If non-zero, the clock will pause during WritePacket for this amount of + // time. + QuicTime::Delta write_pause_time_delta_; DISALLOW_COPY_AND_ASSIGN(TestPacketWriter); }; @@ -597,7 +614,7 @@ MockPacketWriterFactory(QuicPacketWriter* writer) { ON_CALL(*this, Create(_)).WillByDefault(Return(writer)); } - virtual ~MockPacketWriterFactory() {} + ~MockPacketWriterFactory() override {} MOCK_CONST_METHOD1(Create, QuicPacketWriter*(QuicConnection* connection)); }; @@ -611,7 +628,7 @@ send_algorithm_(new StrictMock<MockSendAlgorithm>), loss_algorithm_(new MockLossAlgorithm()), helper_(new TestConnectionHelper(&clock_, &random_generator_)), - writer_(new TestPacketWriter(version())), + writer_(new TestPacketWriter(version(), &clock_)), factory_(writer_.get()), connection_(connection_id_, IPEndPoint(), helper_.get(), factory_, false, version()), @@ -974,6 +991,10 @@ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1)); } + void SetWritePauseTimeDelta(QuicTime::Delta delta) { + writer_->SetWritePauseTimeDelta(delta); + } + void CongestionBlockWrites() { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).WillRepeatedly( @@ -1548,6 +1569,74 @@ EXPECT_EQ(7u, least_unacked()); } +// If FLAGS_quic_record_send_time_before_write is disabled, QuicConnection +// should record the packet sen-tdime after the packet is sent. +TEST_P(QuicConnectionTest, RecordSentTimeAfterPacketSent) { + ValueRestore<bool> old_flag(&FLAGS_quic_record_send_time_before_write, false); + // We're using a MockClock for the tests, so we have complete control over the + // time. + // Our recorded timestamp for the last packet sent time will be passed in to + // the send_algorithm. Make sure that it is set to the correct value. + QuicTime actual_recorded_send_time = QuicTime::Zero(); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true))); + + // First send without any pause and check the result. + QuicTime expected_recorded_send_time = clock_.Now(); + connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr); + EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time) + << "Expected time = " << expected_recorded_send_time.ToDebuggingValue() + << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue(); + + // Now pause during the write, and check the results. + actual_recorded_send_time = QuicTime::Zero(); + const QuicTime::Delta kWritePauseTimeDelta = + QuicTime::Delta::FromMilliseconds(5000); + SetWritePauseTimeDelta(kWritePauseTimeDelta); + expected_recorded_send_time = clock_.Now().Add(kWritePauseTimeDelta); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true))); + connection_.SendStreamDataWithString(2, "baz", 0, !kFin, nullptr); + EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time) + << "Expected time = " << expected_recorded_send_time.ToDebuggingValue() + << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue(); +} + +// If FLAGS_quic_record_send_time_before_write is enabled, QuicConnection should +// record the the packet sent-time prior to sending the packet. +TEST_P(QuicConnectionTest, RecordSentTimeBeforePacketSent) { + ValueRestore<bool> old_flag(&FLAGS_quic_record_send_time_before_write, true); + // We're using a MockClock for the tests, so we have complete control over the + // time. + // Our recorded timestamp for the last packet sent time will be passed in to + // the send_algorithm. Make sure that it is set to the correct value. + QuicTime actual_recorded_send_time = QuicTime::Zero(); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true))); + + // First send without any pause and check the result. + QuicTime expected_recorded_send_time = clock_.Now(); + connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr); + EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time) + << "Expected time = " << expected_recorded_send_time.ToDebuggingValue() + << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue(); + + // Now pause during the write, and check the results. + actual_recorded_send_time = QuicTime::Zero(); + const QuicTime::Delta kWritePauseTimeDelta = + QuicTime::Delta::FromMilliseconds(5000); + SetWritePauseTimeDelta(kWritePauseTimeDelta); + expected_recorded_send_time = clock_.Now(); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true))); + connection_.SendStreamDataWithString(2, "baz", 0, !kFin, nullptr); + EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time) + << "Expected time = " << expected_recorded_send_time.ToDebuggingValue() + << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue(); +} + TEST_P(QuicConnectionTest, FECSending) { // All packets carry version info till version is negotiated. QuicPacketCreator* creator = @@ -1565,7 +1654,8 @@ creator->set_max_packet_length(length); // Send 4 protected data packets, which should also trigger 1 FEC packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(5); + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(5); // The first stream frame will have 2 fewer overhead bytes than the other 3. const string payload(payload_length * 4 + 2, 'a'); connection_.SendStreamDataWithStringWithFec(1, payload, 0, !kFin, nullptr); @@ -1601,7 +1691,8 @@ &connection_)->IsFecEnabled()); // 1 Data and 1 FEC packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(2); connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); const QuicTime::Delta retransmission_time = @@ -1620,8 +1711,9 @@ EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator( &connection_)->IsFecEnabled()); - // 1 Data and 1 FEC packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6); + // 3 Data and 3 FEC packets. + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6); connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); // Send some more data afterwards to ensure early retransmit doesn't trigger. connection_.SendStreamDataWithStringWithFec(3, "foo", 3, !kFin, nullptr); @@ -1648,8 +1740,9 @@ EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator( &connection_)->IsFecEnabled()); - // 1 Data and 1 FEC packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6); + // 3 Data and 3 FEC packet. + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6); connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); // Send some more data afterwards to ensure early retransmit doesn't trigger. connection_.SendStreamDataWithStringWithFec(3, "foo", 3, !kFin, nullptr); @@ -3070,22 +3163,25 @@ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } -TEST_P(QuicConnectionTest, SendEarlyDelayedAckForCrypto) { - QuicTime ack_time = clock_.ApproximateNow(); +TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); - // Process a packet from the crypto stream, which is frame1_'s default. ProcessPacket(1); - // Check if delayed ack timer is running for the expected interval. + // Check that ack is sent and that delayed ack alarm is set. + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + QuicTime ack_time = clock_.ApproximateNow().Add(DefaultDelayedAckTime()); + EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); + + // Completing the handshake as the server does nothing. + QuicConnectionPeer::SetIsServer(&connection_, true); + connection_.OnHandshakeComplete(); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - // Simulate delayed ack alarm firing. - connection_.GetAckAlarm()->Fire(); - // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + + // Complete the handshake as the client decreases the delayed ack time to 0ms. + QuicConnectionPeer::SetIsServer(&connection_, false); + connection_.OnHandshakeComplete(); + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_EQ(clock_.ApproximateNow(), connection_.GetAckAlarm()->deadline()); } TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) {
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index 1df2313..8e14d77 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -34,6 +34,8 @@ stream_(new QuicCryptoClientStream(server_id_, session_.get(), nullptr, &crypto_config_)) { session_->SetCryptoStream(stream_.get()); + // Advance the time, because timers do not like uninitialized times. + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); } void CompleteCryptoHandshake() { @@ -128,8 +130,8 @@ // Advance time 5 years to ensure that we pass the expiry time of the cached // server config. - reinterpret_cast<MockClock*>(const_cast<QuicClock*>(connection_->clock())) - ->AdvanceTime(QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5)); + connection_->AdvanceTime( + QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5)); // Check that a client hello was sent and that CryptoConnect doesn't fail // with an error.
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index 1d62376..c4b5893 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc
@@ -245,8 +245,8 @@ void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) { } -CachedNetworkParameters* -QuicCryptoServerStream::get_previous_cached_network_params() { +const CachedNetworkParameters* +QuicCryptoServerStream::previous_cached_network_params() const { return previous_cached_network_params_.get(); }
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h index 09d9bd8..f88affe 100644 --- a/net/quic/quic_crypto_server_stream.h +++ b/net/quic/quic_crypto_server_stream.h
@@ -82,6 +82,8 @@ void set_previous_cached_network_params( CachedNetworkParameters cached_network_params); + const CachedNetworkParameters* previous_cached_network_params() const; + protected: virtual QuicErrorCode ProcessClientHello( const CryptoHandshakeMessage& message, @@ -93,8 +95,6 @@ // before going through the parameter negotiation step. virtual void OverrideQuicConfigDefaults(QuicConfig* config); - CachedNetworkParameters* get_previous_cached_network_params(); - private: friend class test::CryptoTestUtils;
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index 47d58ce..e737933 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc
@@ -54,3 +54,14 @@ // If true, QUIC connections will delay moving to forward security until the // client starts sending foward secure encrypted packets. bool FLAGS_enable_quic_delay_forward_security = true; + +// Do not flip this flag. jokulik plans more testing and additional monitoring +// before the flag can go the auto-flip process. +// +// If true, record the timestamp for the last sent new packet before the call to +// WritePacket, rather than after in QUIC. +bool FLAGS_quic_record_send_time_before_write = false; + +// If true, enables the QUIC bandwidth resumption experiment (triggered by +// Chrome/Finch). +bool FLAGS_quic_enable_bandwidth_resumption_experiment = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index a75f79b..2ffe618 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h
@@ -20,5 +20,8 @@ NET_EXPORT_PRIVATE extern bool FLAGS_allow_truncated_connection_ids_for_quic; NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets; NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_delay_forward_security; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_record_send_time_before_write; +NET_EXPORT_PRIVATE +extern bool FLAGS_quic_enable_bandwidth_resumption_experiment; #endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index 4e03e3a..578acea 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc
@@ -87,8 +87,7 @@ server_framer_.set_visitor(&framer_visitor_); } - virtual ~QuicPacketCreatorTest() override { - } + ~QuicPacketCreatorTest() override {} void ProcessPacket(QuicPacket* packet) { scoped_ptr<QuicEncryptedPacket> encrypted(
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc index 3f2472c..ac99144 100644 --- a/net/quic/quic_packet_generator_test.cc +++ b/net/quic/quic_packet_generator_test.cc
@@ -33,7 +33,7 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface { public: MockDelegate() {} - virtual ~MockDelegate() override {} + ~MockDelegate() override {} MOCK_METHOD3(ShouldGeneratePacket, bool(TransmissionType transmission_type, @@ -116,7 +116,7 @@ packet6_(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, nullptr), packet7_(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, nullptr) {} - virtual ~QuicPacketGeneratorTest() override { + ~QuicPacketGeneratorTest() override { delete packet_.packet; delete packet_.retransmittable_frames; delete packet2_.packet;
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 5aa831e..b631b07 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc
@@ -704,7 +704,8 @@ transmission_type(NOT_RETRANSMISSION), all_transmissions(nullptr), in_flight(false), - is_unackable(false) {} + is_unackable(false), + is_fec_packet(false) {} TransmissionInfo::TransmissionInfo( RetransmittableFrames* retransmittable_frames, @@ -719,6 +720,7 @@ transmission_type(transmission_type), all_transmissions(nullptr), in_flight(false), - is_unackable(false) {} + is_unackable(false), + is_fec_packet(false) {} } // namespace net
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 00064ff..4cd53a9 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h
@@ -1099,6 +1099,8 @@ bool in_flight; // True if the packet can never be acked, so it can be removed. bool is_unackable; + // True if the packet is an FEC packet. + bool is_fec_packet; }; } // namespace net
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index 7978fed..142871e 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc
@@ -163,6 +163,11 @@ } } +void QuicSentPacketManager::ResumeConnectionState( + const CachedNetworkParameters& cached_network_params) { + send_algorithm_->ResumeConnectionState(cached_network_params); +} + void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) { if (n_connection_simulation_) { // Ensure the number of connections is between 1 and 5. @@ -323,6 +328,9 @@ (retransmission_type == ALL_UNACKED_RETRANSMISSION || frames->encryption_level() == ENCRYPTION_INITIAL)) { MarkForRetransmission(sequence_number, retransmission_type); + } else if (it->is_fec_packet) { + // Remove FEC packets from the packet map, since we can't retransmit them. + unacked_packets_.RemoveFromInFlight(sequence_number); } } } @@ -549,12 +557,18 @@ } // Only track packets as in flight that the send algorithm wants us to track. + // Since FEC packets should also be counted towards the congestion window, + // consider them as retransmittable for the purposes of congestion control. + HasRetransmittableData has_congestion_controlled_data = + serialized_packet->packet->is_fec_packet() ? + HAS_RETRANSMITTABLE_DATA : has_retransmittable_data; const bool in_flight = send_algorithm_->OnPacketSent(sent_time, unacked_packets_.bytes_in_flight(), sequence_number, bytes, - has_retransmittable_data); + has_congestion_controlled_data); + unacked_packets_.AddSentPacket(*serialized_packet, original_sequence_number, transmission_type,
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h index 2a3ea64..2a94e09 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h
@@ -16,6 +16,7 @@ #include "net/quic/congestion_control/loss_detection_interface.h" #include "net/quic/congestion_control/rtt_stats.h" #include "net/quic/congestion_control/send_algorithm_interface.h" +#include "net/quic/crypto/cached_network_parameters.h" #include "net/quic/quic_ack_notifier_manager.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_sustained_bandwidth_recorder.h" @@ -99,6 +100,10 @@ virtual void SetFromConfig(const QuicConfig& config); + // Pass the CachedNetworkParameters to the send algorithm. + void ResumeConnectionState( + const CachedNetworkParameters& cached_network_params); + void SetNumOpenStreams(size_t num_streams); void SetHandshakeConfirmed() { handshake_confirmed_ = true; } @@ -111,6 +116,13 @@ bool IsUnacked(QuicPacketSequenceNumber sequence_number) const; // Requests retransmission of all unacked packets of |retransmission_type|. + // The behavior of this method depends on the value of |retransmission_type|: + // ALL_UNACKED_RETRANSMISSION - All unacked packets will be retransmitted. + // This can happen, for example, after a version negotiation packet has been + // received and all packets needs to be retransmitted with the new version. + // ALL_INITIAL_RETRANSMISSION - Only initially encrypted packets will be + // retransmitted. This can happen, for example, when a CHLO has been rejected + // and the previously encrypted data needs to be encrypted with a new key. void RetransmitUnackedPackets(TransmissionType retransmission_type); // Retransmits the oldest pending packet there is still a tail loss probe
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index d710120..c1e6f20 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -64,9 +64,7 @@ EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber()); } - virtual ~QuicSentPacketManagerTest() override { - STLDeleteElements(&packets_); - } + ~QuicSentPacketManagerTest() override { STLDeleteElements(&packets_); } QuicByteCount BytesInFlight() { return QuicSentPacketManagerPeer::GetBytesInFlight(&manager_); @@ -216,7 +214,7 @@ void SendFecPacket(QuicPacketSequenceNumber sequence_number) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), sequence_number, - kDefaultLength, NO_RETRANSMITTABLE_DATA)) + kDefaultLength, HAS_RETRANSMITTABLE_DATA)) .Times(1).WillOnce(Return(true)); SerializedPacket packet(CreateFecPacket(sequence_number)); manager_.OnPacketSent(&packet, 0, clock_.Now(),
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc index 1d48182..e0defd6 100644 --- a/net/quic/quic_server_session.cc +++ b/net/quic/quic_server_session.cc
@@ -37,14 +37,29 @@ void QuicServerSession::OnConfigNegotiated() { QuicSession::OnConfigNegotiated(); - if (!FLAGS_enable_quic_fec || - !config()->HasReceivedConnectionOptions() || - !ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) { + + if (!config()->HasReceivedConnectionOptions()) { return; } - // kFHDR config maps to FEC protection always for headers stream. - // TODO(jri): Add crypto stream in addition to headers for kHDR. - headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS); + + // If the client has provided a bandwidth estimate from the same serving + // region, then pass it to the sent packet manager in preparation for possible + // bandwidth resumption. + const CachedNetworkParameters* cached_network_params = + crypto_stream_->previous_cached_network_params(); + if (FLAGS_quic_enable_bandwidth_resumption_experiment && + cached_network_params != nullptr && + ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE) && + cached_network_params->serving_region() == serving_region_) { + connection()->ResumeConnectionState(*cached_network_params); + } + + if (FLAGS_enable_quic_fec && + ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) { + // kFHDR config maps to FEC protection always for headers stream. + // TODO(jri): Add crypto stream in addition to headers for kHDR. + headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS); + } } void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 2318ab4..e4b163f 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc
@@ -48,8 +48,8 @@ session_->PostProcessAfterData(); } - void OnWindowUpdateFrames(const vector<QuicWindowUpdateFrame>& frames) - override { + void OnWindowUpdateFrames( + const vector<QuicWindowUpdateFrame>& frames) override { session_->OnWindowUpdateFrames(frames); session_->PostProcessAfterData(); }
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index d14d875..d953678 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc
@@ -54,8 +54,7 @@ : QuicCryptoStream(session) { } - virtual void OnHandshakeMessage( - const CryptoHandshakeMessage& message) override { + void OnHandshakeMessage(const CryptoHandshakeMessage& message) override { encryption_established_ = true; handshake_confirmed_ = true; CryptoHandshakeMessage msg; @@ -94,7 +93,7 @@ using ReliableQuicStream::CloseWriteSide; - virtual uint32 ProcessData(const char* data, uint32 data_len) override { + uint32 ProcessData(const char* data, uint32 data_len) override { return data_len; } @@ -131,17 +130,15 @@ InitializeSession(); } - virtual TestCryptoStream* GetCryptoStream() override { - return &crypto_stream_; - } + TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; } - virtual TestStream* CreateOutgoingDataStream() override { + TestStream* CreateOutgoingDataStream() override { TestStream* stream = new TestStream(GetNextStreamId(), this); ActivateStream(stream); return stream; } - virtual TestStream* CreateIncomingDataStream(QuicStreamId id) override { + TestStream* CreateIncomingDataStream(QuicStreamId id) override { return new TestStream(id, this); } @@ -153,7 +150,7 @@ return QuicSession::GetIncomingDataStream(stream_id); } - virtual QuicConsumedData WritevData( + QuicConsumedData WritevData( QuicStreamId id, const IOVector& data, QuicStreamOffset offset, @@ -223,6 +220,7 @@ "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn" "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr" "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo "; + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); } void CheckClosedStreams() {
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index 8c90c9f..43a105b 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc
@@ -44,7 +44,7 @@ const string& details)); MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error)); MOCK_METHOD0(OnCanWrite, void()); - virtual QuicPriority EffectivePriority() const override { + QuicPriority EffectivePriority() const override { return QuicUtils::HighestPriority(); } virtual bool IsFlowControlEnabled() const {
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h index 53e5ebe..62bf582 100644 --- a/net/quic/quic_time.h +++ b/net/quic/quic_time.h
@@ -17,6 +17,8 @@ namespace net { +static const int kNumSecondsPerMinute = 60; +static const int kNumSecondsPerHour = kNumSecondsPerMinute * 60; static const uint64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond; static const uint64 kNumMicrosPerMilli = base::Time::kMicrosecondsPerMillisecond;
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc index 04eb1b8..bbff3c9 100644 --- a/net/quic/quic_unacked_packet_map.cc +++ b/net/quic/quic_unacked_packet_map.cc
@@ -53,6 +53,9 @@ packet.sequence_number_length, transmission_type, sent_time); + DCHECK(packet.packet != nullptr); + info.is_fec_packet = packet.packet->is_fec_packet(); + if (old_sequence_number == 0) { if (packet.retransmittable_frames != nullptr && packet.retransmittable_frames->HasCryptoHandshake() == IS_HANDSHAKE) {
diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc index d31ce44..7840495 100644 --- a/net/quic/quic_unacked_packet_map_test.cc +++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -8,6 +8,7 @@ #include "testing/gtest/include/gtest/gtest.h" using std::min; +using std::vector; namespace net { namespace test { @@ -23,16 +24,26 @@ : now_(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1000))) { } + ~QuicUnackedPacketMapTest() override { + STLDeleteElements(&packets_); + } + SerializedPacket CreateRetransmittablePacket( QuicPacketSequenceNumber sequence_number) { + packets_.push_back(QuicPacket::NewDataPacket( + nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false, + PACKET_1BYTE_SEQUENCE_NUMBER)); return SerializedPacket(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, - nullptr, 0, new RetransmittableFrames()); + packets_.back(), 0, new RetransmittableFrames()); } SerializedPacket CreateNonRetransmittablePacket( QuicPacketSequenceNumber sequence_number) { + packets_.push_back(QuicPacket::NewDataPacket( + nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false, + PACKET_1BYTE_SEQUENCE_NUMBER)); return SerializedPacket(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, - nullptr, 0, nullptr); + packets_.back(), 0, nullptr); } void VerifyInFlightPackets(QuicPacketSequenceNumber* packets, @@ -94,7 +105,7 @@ << " packets[" << i << "]:" << packets[i]; } } - + vector<QuicPacket*> packets_; QuicUnackedPacketMap unacked_packets_; QuicTime now_; }; @@ -185,8 +196,8 @@ unacked_packets_.RemoveFromInFlight(2); QuicPacketSequenceNumber unacked2[] = { 1 }; - VerifyUnackedPackets(unacked, arraysize(unacked2)); - VerifyInFlightPackets(unacked, arraysize(unacked2)); + VerifyUnackedPackets(unacked2, arraysize(unacked2)); + VerifyInFlightPackets(unacked2, arraysize(unacked2)); VerifyRetransmittablePackets(nullptr, 0); unacked_packets_.RemoveFromInFlight(1);
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index 814be7b..b24316f 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -214,6 +214,8 @@ QuicCryptoServerStream* server, const FakeClientOptions& options) { PacketSavingConnection* client_conn = new PacketSavingConnection(false); + // Advance the time, because timers do not like uninitialized times. + client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1)); TestClientSession client_session(client_conn, DefaultQuicConfig()); QuicCryptoClientConfig crypto_config;
diff --git a/net/quic/test_tools/mock_quic_dispatcher.h b/net/quic/test_tools/mock_quic_dispatcher.h index f923790..4945724 100644 --- a/net/quic/test_tools/mock_quic_dispatcher.h +++ b/net/quic/test_tools/mock_quic_dispatcher.h
@@ -22,7 +22,7 @@ PacketWriterFactory* packet_writer_factory, QuicConnectionHelperInterface* helper); - virtual ~MockQuicDispatcher(); + ~MockQuicDispatcher() override; MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address, const IPEndPoint& client_address,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index fa987de..9df03eb 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -10,6 +10,7 @@ #include <string> #include <vector> +#include "base/basictypes.h" #include "base/strings/string_piece.h" #include "net/quic/congestion_control/loss_detection_interface.h" #include "net/quic/congestion_control/send_algorithm_interface.h" @@ -31,7 +32,7 @@ namespace test { static const QuicConnectionId kTestConnectionId = 42; -static const int kTestPort = 123; +static const uint16 kTestPort = 123; static const uint32 kInitialStreamFlowControlWindowForTest = 32 * 1024; // 32 KB static const uint32 kInitialSessionFlowControlWindowForTest = @@ -150,7 +151,7 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { public: MockFramerVisitor(); - virtual ~MockFramerVisitor(); + ~MockFramerVisitor() override; MOCK_METHOD1(OnError, void(QuicFramer* framer)); // The constructor sets this up to return false by default. @@ -225,7 +226,7 @@ class MockConnectionVisitor : public QuicConnectionVisitorInterface { public: MockConnectionVisitor(); - virtual ~MockConnectionVisitor(); + ~MockConnectionVisitor() override; MOCK_METHOD1(OnStreamFrames, void(const std::vector<QuicStreamFrame>& frame)); MOCK_METHOD1(OnWindowUpdateFrames, @@ -293,7 +294,7 @@ // Uses a Mock helper, ConnectionId of 42, and 127.0.0.1:123. MockConnection(bool is_server, const QuicVersionVector& supported_versions); - virtual ~MockConnection(); + ~MockConnection() override; // If the constructor that uses a MockHelper has been used then this method // will advance the time of the MockClock. @@ -324,7 +325,7 @@ QuicConnection::ProcessUdpPacket(self_address, peer_address, packet); } - virtual bool OnProtocolVersionMismatch(QuicVersion version) override { + bool OnProtocolVersionMismatch(QuicVersion version) override { return false; } @@ -355,7 +356,7 @@ class MockSession : public QuicSession { public: explicit MockSession(QuicConnection* connection); - virtual ~MockSession(); + ~MockSession() override; MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer)); MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id)); MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*()); @@ -388,14 +389,14 @@ class TestSession : public QuicSession { public: TestSession(QuicConnection* connection, const QuicConfig& config); - virtual ~TestSession(); + ~TestSession() override; MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id)); MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*()); void SetCryptoStream(QuicCryptoStream* stream); - virtual QuicCryptoStream* GetCryptoStream() override; + QuicCryptoStream* GetCryptoStream() override; private: QuicCryptoStream* crypto_stream_; @@ -406,7 +407,7 @@ class TestClientSession : public QuicClientSessionBase { public: TestClientSession(QuicConnection* connection, const QuicConfig& config); - virtual ~TestClientSession(); + ~TestClientSession() override; // QuicClientSessionBase MOCK_METHOD1(OnProofValid, @@ -420,7 +421,7 @@ void SetCryptoStream(QuicCryptoStream* stream); - virtual QuicCryptoStream* GetCryptoStream() override; + QuicCryptoStream* GetCryptoStream() override; private: QuicCryptoStream* crypto_stream_; @@ -431,7 +432,7 @@ class MockPacketWriter : public QuicPacketWriter { public: MockPacketWriter(); - virtual ~MockPacketWriter(); + ~MockPacketWriter() override; MOCK_METHOD4(WritePacket, WriteResult(const char* buffer, @@ -449,7 +450,7 @@ class MockSendAlgorithm : public SendAlgorithmInterface { public: MockSendAlgorithm(); - virtual ~MockSendAlgorithm(); + ~MockSendAlgorithm() override; MOCK_METHOD3(SetFromConfig, void(const QuicConfig& config, bool is_server, @@ -482,6 +483,7 @@ MOCK_CONST_METHOD0(InRecovery, bool()); MOCK_CONST_METHOD0(GetSlowStartThreshold, QuicByteCount()); MOCK_CONST_METHOD0(GetCongestionControlType, CongestionControlType()); + MOCK_METHOD1(ResumeConnectionState, void(const CachedNetworkParameters&)); private: DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm); @@ -490,7 +492,7 @@ class MockLossAlgorithm : public LossDetectionInterface { public: MockLossAlgorithm(); - virtual ~MockLossAlgorithm(); + ~MockLossAlgorithm() override; MOCK_CONST_METHOD0(GetLossDetectionType, LossDetectionType()); MOCK_METHOD4(DetectLostPackets, @@ -520,7 +522,7 @@ class MockEntropyCalculator : public TestEntropyCalculator { public: MockEntropyCalculator(); - virtual ~MockEntropyCalculator(); + ~MockEntropyCalculator() override; MOCK_CONST_METHOD1( EntropyHash, @@ -542,7 +544,7 @@ protected: // Object is ref counted. - virtual ~MockAckNotifierDelegate(); + ~MockAckNotifierDelegate() override; private: DISALLOW_COPY_AND_ASSIGN(MockAckNotifierDelegate); @@ -552,7 +554,7 @@ public QuicSentPacketManager::NetworkChangeVisitor { public: MockNetworkChangeVisitor(); - virtual ~MockNetworkChangeVisitor(); + ~MockNetworkChangeVisitor() override; MOCK_METHOD0(OnCongestionWindowChange, void());
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc index b996127..bc7d111 100644 --- a/net/socket/client_socket_pool_manager.cc +++ b/net/socket/client_socket_pool_manager.cc
@@ -91,9 +91,7 @@ bool using_ssl = request_url.SchemeIs("https") || request_url.SchemeIs("wss") || force_spdy_over_ssl; - HostPortPair origin_host_port = - HostPortPair(request_url.HostNoBrackets(), - request_url.EffectiveIntPort()); + HostPortPair origin_host_port = HostPortPair::FromURL(request_url); if (!using_ssl && session->params().testing_fixed_http_port != 0) { origin_host_port.set_port(session->params().testing_fixed_http_port);
diff --git a/net/socket/server_socket.cc b/net/socket/server_socket.cc index da89b46..7cf6c64 100644 --- a/net/socket/server_socket.cc +++ b/net/socket/server_socket.cc
@@ -17,7 +17,7 @@ } int ServerSocket::ListenWithAddressAndPort(const std::string& address_string, - int port, + uint16 port, int backlog) { IPAddressNumber address_number; if (!ParseIPLiteralToNumber(address_string, &address_number)) {
diff --git a/net/socket/server_socket.h b/net/socket/server_socket.h index 4b9ca8e..828b399 100644 --- a/net/socket/server_socket.h +++ b/net/socket/server_socket.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "net/base/completion_callback.h" #include "net/base/net_export.h" @@ -30,7 +31,7 @@ // Subclasses may override this function if |address_string| is in a different // format, for example, unix domain socket path. virtual int ListenWithAddressAndPort(const std::string& address_string, - int port, + uint16 port, int backlog); // Gets current address the socket is bound to.
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 5ae4eee..308de2e 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc
@@ -682,7 +682,7 @@ new MockUDPClientSocket(data_provider, net_log)); data_provider->set_socket(socket.get()); if (bind_type == DatagramSocket::RANDOM_BIND) - socket->set_source_port(rand_int_cb.Run(1025, 65535)); + socket->set_source_port(static_cast<uint16>(rand_int_cb.Run(1025, 65535))); return socket.Pass(); } @@ -1917,7 +1917,7 @@ data_provider->set_delegate(socket->AsWeakPtr()); udp_client_sockets().push_back(socket.get()); if (bind_type == DatagramSocket::RANDOM_BIND) - socket->set_source_port(rand_int_cb.Run(1025, 65535)); + socket->set_source_port(static_cast<uint16>(rand_int_cb.Run(1025, 65535))); return socket.Pass(); }
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index 7bccdae..7b45c0c 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h
@@ -881,13 +881,13 @@ void OnReadComplete(const MockRead& data) override; void OnConnectComplete(const MockConnect& data) override; - void set_source_port(int port) { source_port_ = port; } + void set_source_port(uint16 port) { source_port_ = port; } private: bool connected_; IPEndPoint peer_address_; DeterministicSocketHelper helper_; - int source_port_; // Ephemeral source port. + uint16 source_port_; // Ephemeral source port. DISALLOW_COPY_AND_ASSIGN(DeterministicMockUDPClientSocket); }; @@ -1051,7 +1051,7 @@ void OnReadComplete(const MockRead& data) override; void OnConnectComplete(const MockConnect& data) override; - void set_source_port(int port) { source_port_ = port;} + void set_source_port(uint16 port) { source_port_ = port;} private: int CompleteRead(); @@ -1064,7 +1064,7 @@ int read_offset_; MockRead read_data_; bool need_read_data_; - int source_port_; // Ephemeral source port. + uint16 source_port_; // Ephemeral source port. // Address of the "remote" peer we're connected to. IPEndPoint peer_addr_;
diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc index c474a0b..5bcc146 100644 --- a/net/socket/socks5_client_socket_unittest.cc +++ b/net/socket/socks5_client_socket_unittest.cc
@@ -258,7 +258,7 @@ const char partial1[] = { 0x05, 0x01 }; const char partial2[] = { 0x00 }; MockWrite data_writes[] = { - MockWrite(ASYNC, arraysize(partial1)), + MockWrite(ASYNC, partial1, arraysize(partial1)), MockWrite(ASYNC, partial2, arraysize(partial2)), MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest)) }; MockRead data_reads[] = {
diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc index fbb84f8..01bffe6 100644 --- a/net/socket/socks_client_socket_unittest.cc +++ b/net/socket/socks_client_socket_unittest.cc
@@ -287,12 +287,12 @@ const char kSOCKSPartialRequest2[] = { 0x00, 0x50, 127, 0, 0, 1, 0 }; MockWrite data_writes[] = { - MockWrite(ASYNC, arraysize(kSOCKSPartialRequest1)), + MockWrite(ASYNC, kSOCKSPartialRequest1, arraysize(kSOCKSPartialRequest1)), // simulate some empty writes MockWrite(ASYNC, 0), MockWrite(ASYNC, 0), - MockWrite(ASYNC, kSOCKSPartialRequest2, - arraysize(kSOCKSPartialRequest2)) }; + MockWrite(ASYNC, kSOCKSPartialRequest2, arraysize(kSOCKSPartialRequest2)), + }; MockRead data_reads[] = { MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply)) }; CapturingNetLog log;
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 57aa619..05eb1cb 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc
@@ -17,6 +17,7 @@ #include "base/environment.h" #include "base/memory/singleton.h" #include "base/metrics/histogram.h" +#include "base/profiler/scoped_tracker.h" #include "base/strings/string_piece.h" #include "base/synchronization/lock.h" #include "crypto/ec_private_key.h" @@ -899,10 +900,20 @@ } int SSLClientSocketOpenSSL::DoHandshake() { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "424386 SSLClientSocketOpenSSL::DoHandshake1")); + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); int net_error = OK; int rv = SSL_do_handshake(ssl_); + // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "424386 SSLClientSocketOpenSSL::DoHandshake2")); + if (client_auth_cert_needed_) { net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; // If the handshake already succeeded (because the server requests but @@ -1608,6 +1619,11 @@ } int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "424386 SSLClientSocketOpenSSL::ClientCertRequestCallback")); + DVLOG(3) << "OpenSSL ClientCertRequestCallback called"; DCHECK(ssl == ssl_); @@ -1705,6 +1721,11 @@ } int SSLClientSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "424386 SSLClientSocketOpenSSL::CertVerifyCallback")); + if (!completed_connect_) { // If the first handshake hasn't completed then we accept any certificates // because we verify after the handshake. @@ -1739,6 +1760,11 @@ unsigned char* outlen, const unsigned char* in, unsigned int inlen) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "424386 SSLClientSocketOpenSSL::SelectNextProtoCallback")); + if (ssl_config_.next_protos.empty()) { *out = reinterpret_cast<uint8*>( const_cast<char*>(kDefaultSupportedNPNProtocol));
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc index 8ac29ef..23bb111 100644 --- a/net/socket/ssl_client_socket_pool_unittest.cc +++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -239,8 +239,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, SSLClientSocketPoolTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); // Tests that the final socket will connect even if all sockets // prior to it fail.
diff --git a/net/socket/tcp_listen_socket.cc b/net/socket/tcp_listen_socket.cc index 585c412..11b2390 100644 --- a/net/socket/tcp_listen_socket.cc +++ b/net/socket/tcp_listen_socket.cc
@@ -31,7 +31,9 @@ // static scoped_ptr<TCPListenSocket> TCPListenSocket::CreateAndListen( - const string& ip, int port, StreamListenSocket::Delegate* del) { + const string& ip, + uint16 port, + StreamListenSocket::Delegate* del) { SocketDescriptor s = CreateAndBind(ip, port); if (s == kInvalidSocket) return scoped_ptr<TCPListenSocket>(); @@ -47,7 +49,7 @@ TCPListenSocket::~TCPListenSocket() {} -SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, int port) { +SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, uint16 port) { SocketDescriptor s = CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s != kInvalidSocket) { #if defined(OS_POSIX) @@ -74,7 +76,7 @@ } SocketDescriptor TCPListenSocket::CreateAndBindAnyPort(const string& ip, - int* port) { + uint16* port) { SocketDescriptor s = CreateAndBind(ip, 0); if (s == kInvalidSocket) return kInvalidSocket; @@ -110,16 +112,4 @@ socket_delegate_->DidAccept(this, sock.Pass()); } -TCPListenSocketFactory::TCPListenSocketFactory(const string& ip, int port) - : ip_(ip), - port_(port) { -} - -TCPListenSocketFactory::~TCPListenSocketFactory() {} - -scoped_ptr<StreamListenSocket> TCPListenSocketFactory::CreateAndListen( - StreamListenSocket::Delegate* delegate) const { - return TCPListenSocket::CreateAndListen(ip_, port_, delegate); -} - } // namespace net
diff --git a/net/socket/tcp_listen_socket.h b/net/socket/tcp_listen_socket.h index 1702e50..01a08a1 100644 --- a/net/socket/tcp_listen_socket.h +++ b/net/socket/tcp_listen_socket.h
@@ -21,14 +21,16 @@ // Listen on port for the specified IP address. Use 127.0.0.1 to only // accept local connections. static scoped_ptr<TCPListenSocket> CreateAndListen( - const std::string& ip, int port, StreamListenSocket::Delegate* del); + const std::string& ip, + uint16 port, + StreamListenSocket::Delegate* del); // Get raw TCP socket descriptor bound to ip:port. - static SocketDescriptor CreateAndBind(const std::string& ip, int port); + static SocketDescriptor CreateAndBind(const std::string& ip, uint16 port); // Get raw TCP socket descriptor bound to ip and return port it is bound to. static SocketDescriptor CreateAndBindAnyPort(const std::string& ip, - int* port); + uint16* port); protected: TCPListenSocket(SocketDescriptor s, StreamListenSocket::Delegate* del); @@ -40,23 +42,6 @@ DISALLOW_COPY_AND_ASSIGN(TCPListenSocket); }; -// Factory that can be used to instantiate TCPListenSocket. -class NET_EXPORT TCPListenSocketFactory : public StreamListenSocketFactory { - public: - TCPListenSocketFactory(const std::string& ip, int port); - ~TCPListenSocketFactory() override; - - // StreamListenSocketFactory overrides. - scoped_ptr<StreamListenSocket> CreateAndListen( - StreamListenSocket::Delegate* delegate) const override; - - private: - const std::string ip_; - const int port_; - - DISALLOW_COPY_AND_ASSIGN(TCPListenSocketFactory); -}; - } // namespace net #endif // NET_SOCKET_TCP_LISTEN_SOCKET_H_
diff --git a/net/socket/tcp_server_socket_unittest.cc b/net/socket/tcp_server_socket_unittest.cc index 01bae9f..2f6491b 100644 --- a/net/socket/tcp_server_socket_unittest.cc +++ b/net/socket/tcp_server_socket_unittest.cc
@@ -50,7 +50,7 @@ *success = true; } - void ParseAddress(std::string ip_str, int port, IPEndPoint* address) { + void ParseAddress(std::string ip_str, uint16 port, IPEndPoint* address) { IPAddressNumber ip_number; bool rv = ParseIPLiteralToNumber(ip_str, &ip_number); if (!rv)
diff --git a/net/socket/tcp_socket_unittest.cc b/net/socket/tcp_socket_unittest.cc index 1981388..4bfc138 100644 --- a/net/socket/tcp_socket_unittest.cc +++ b/net/socket/tcp_socket_unittest.cc
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "net/base/address_list.h" @@ -56,7 +57,9 @@ *success = true; } - void ParseAddress(const std::string& ip_str, int port, IPEndPoint* address) { + void ParseAddress(const std::string& ip_str, + uint16 port, + IPEndPoint* address) { IPAddressNumber ip_number; bool rv = ParseIPLiteralToNumber(ip_str, &ip_number); if (!rv)
diff --git a/net/socket/transport_client_socket_unittest.cc b/net/socket/transport_client_socket_unittest.cc index d01cbad..e4e060a 100644 --- a/net/socket/transport_client_socket_unittest.cc +++ b/net/socket/transport_client_socket_unittest.cc
@@ -89,7 +89,7 @@ } protected: - int listen_port_; + uint16 listen_port_; CapturingNetLog net_log_; ClientSocketFactory* const socket_factory_; scoped_ptr<StreamSocket> sock_; @@ -105,10 +105,10 @@ // Find a free port to listen on scoped_ptr<TCPListenSocket> sock; - int port; + uint16 port; // Range of ports to listen on. Shouldn't need to try many. - const int kMinPort = 10100; - const int kMaxPort = 10200; + const uint16 kMinPort = 10100; + const uint16 kMaxPort = 10200; #if defined(OS_WIN) EnsureWinsockInit(); #endif
diff --git a/net/socket/unix_domain_server_socket_posix.cc b/net/socket/unix_domain_server_socket_posix.cc index 4d63283..6866d36 100644 --- a/net/socket/unix_domain_server_socket_posix.cc +++ b/net/socket/unix_domain_server_socket_posix.cc
@@ -67,7 +67,7 @@ int UnixDomainServerSocket::ListenWithAddressAndPort( const std::string& unix_domain_path, - int port_unused, + uint16 port_unused, int backlog) { DCHECK(!listen_socket_);
diff --git a/net/socket/unix_domain_server_socket_posix.h b/net/socket/unix_domain_server_socket_posix.h index 0a26eb3..1097548 100644 --- a/net/socket/unix_domain_server_socket_posix.h +++ b/net/socket/unix_domain_server_socket_posix.h
@@ -53,7 +53,7 @@ // ServerSocket implementation. int Listen(const IPEndPoint& address, int backlog) override; int ListenWithAddressAndPort(const std::string& unix_domain_path, - int port_unused, + uint16 port_unused, int backlog) override; int GetLocalAddress(IPEndPoint* address) const override; int Accept(scoped_ptr<StreamSocket>* socket,
diff --git a/net/spdy/buffered_spdy_framer_unittest.cc b/net/spdy/buffered_spdy_framer_unittest.cc index 11f8d08..5304f08 100644 --- a/net/spdy/buffered_spdy_framer_unittest.cc +++ b/net/spdy/buffered_spdy_framer_unittest.cc
@@ -208,8 +208,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, BufferedSpdyFramerTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); TEST_P(BufferedSpdyFramerTest, OnSetting) { SpdyFramer framer(spdy_version());
diff --git a/net/spdy/hpack_huffman_aggregator.cc b/net/spdy/hpack_huffman_aggregator.cc index 41a3f48..8080a9b 100644 --- a/net/spdy/hpack_huffman_aggregator.cc +++ b/net/spdy/hpack_huffman_aggregator.cc
@@ -49,10 +49,8 @@ if (IsCrossOrigin(request)) { return; } - HostPortPair endpoint = HostPortPair(request.url.HostNoBrackets(), - request.url.EffectiveIntPort()); - HpackEncoder* encoder = ObtainEncoder( - SpdySessionKey(endpoint, proxy, request.privacy_mode)); + HpackEncoder* encoder = ObtainEncoder(SpdySessionKey( + HostPortPair::FromURL(request.url), proxy, request.privacy_mode)); // Convert and encode the request and response header sets. { @@ -108,8 +106,6 @@ bool HpackHuffmanAggregator::IsCrossOrigin(const HttpRequestInfo& request) { // Require that the request is top-level, or that it shares // an origin with its referer. - HostPortPair endpoint = HostPortPair(request.url.HostNoBrackets(), - request.url.EffectiveIntPort()); if ((request.load_flags & LOAD_MAIN_FRAME) == 0) { std::string referer_str; if (!request.extra_headers.GetHeader(HttpRequestHeaders::kReferer, @@ -118,9 +114,8 @@ return true; } GURL referer(referer_str); - HostPortPair referer_endpoint = HostPortPair(referer.HostNoBrackets(), - referer.EffectiveIntPort()); - if (!endpoint.Equals(referer_endpoint)) { + if (!HostPortPair::FromURL(request.url).Equals( + HostPortPair::FromURL(referer))) { // Cross-origin request. return true; }
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index c08b597..f1b1de3 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc
@@ -1991,7 +1991,8 @@ DCHECK(successful_read); if (SpdyConstants::IsValidRstStreamStatus(protocol_version(), status_raw)) { - status = static_cast<SpdyRstStreamStatus>(status_raw); + status = + SpdyConstants::ParseRstStreamStatus(protocol_version(), status_raw); } else { if (protocol_version() > SPDY3) { // Treat unrecognized status codes as INTERNAL_ERROR as @@ -2484,7 +2485,8 @@ builder.BeginNewFrame(*this, RST_STREAM, 0, rst_stream.stream_id()); } - builder.WriteUInt32(rst_stream.status()); + builder.WriteUInt32(SpdyConstants::SerializeRstStreamStatus( + protocol_version(), rst_stream.status())); // In SPDY4 and up, RST_STREAM frames may also specify opaque data. if (protocol_version() > SPDY3 && rst_stream.description().size() > 0) {
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc index 2b7bc4b..2fac61c 100644 --- a/net/spdy/spdy_framer_test.cc +++ b/net/spdy/spdy_framer_test.cc
@@ -2474,7 +2474,7 @@ 0x00, 0x00, 0x04, 0x03, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, - 0x06, + 0x02, }; SpdyRstStreamIR rst_stream(0x7FFFFFFF, RST_STREAM_INTERNAL_ERROR,
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc index 574b76a..f22b75f 100644 --- a/net/spdy/spdy_http_stream_unittest.cc +++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -130,8 +130,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, SpdyHttpStreamTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); // SpdyHttpStream::GetUploadProgress() should still work even before the // stream is initialized. @@ -700,9 +699,6 @@ // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be // made available is handled correctly. TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) { - if (GetParam() < kProtoSPDY3) - return; - scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, true)); MockWrite writes[] = {
diff --git a/net/spdy/spdy_http_utils.cc b/net/spdy/spdy_http_utils.cc index b67e699..fc77f5d 100644 --- a/net/spdy/spdy_http_utils.cc +++ b/net/spdy/spdy_http_utils.cc
@@ -170,42 +170,21 @@ SpdyMajorVersion protocol_version) { DCHECK_GE(priority, MINIMUM_PRIORITY); DCHECK_LE(priority, MAXIMUM_PRIORITY); - if (protocol_version == SPDY2) { - // SPDY 2 only has 2 bits of priority, but we have 5 RequestPriorities. - // Map IDLE => 3, LOWEST => 2, LOW => 2, MEDIUM => 1, HIGHEST => 0. - if (priority > LOWEST) { - return static_cast<SpdyPriority>(HIGHEST - priority); - } else { - return static_cast<SpdyPriority>(HIGHEST - priority - 1); - } - } else { - return static_cast<SpdyPriority>(HIGHEST - priority); - } + return static_cast<SpdyPriority>(MAXIMUM_PRIORITY - priority); } NET_EXPORT_PRIVATE RequestPriority ConvertSpdyPriorityToRequestPriority( SpdyPriority priority, SpdyMajorVersion protocol_version) { - // Handle invalid values gracefully, and pick LOW to map 2 back - // to for SPDY/2. - SpdyPriority idle_cutoff = (protocol_version == SPDY2) ? 3 : 5; - return (priority >= idle_cutoff) ? - IDLE : static_cast<RequestPriority>(HIGHEST - priority); + // Handle invalid values gracefully. + // Note that SpdyPriority is not an enum, hence the magic constants. + return (priority >= 5) ? + IDLE : static_cast<RequestPriority>(4 - priority); } GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers, SpdyMajorVersion protocol_version, bool pushed) { - // SPDY 2 server push urls are specified in a single "url" header. - if (pushed && protocol_version == SPDY2) { - std::string url; - SpdyHeaderBlock::const_iterator it; - it = headers.find("url"); - if (it != headers.end()) - url = it->second; - return GURL(url); - } - const char* scheme_header = protocol_version >= SPDY3 ? ":scheme" : "scheme"; const char* host_header = protocol_version >= SPDY4 ? ":authority" : (protocol_version >= SPDY3 ? ":host" : "host");
diff --git a/net/spdy/spdy_http_utils_unittest.cc b/net/spdy/spdy_http_utils_unittest.cc index d811164..b66534b 100644 --- a/net/spdy/spdy_http_utils_unittest.cc +++ b/net/spdy/spdy_http_utils_unittest.cc
@@ -11,14 +11,6 @@ namespace { -TEST(SpdyHttpUtilsTest, ConvertRequestPriorityToSpdy2Priority) { - EXPECT_EQ(0, ConvertRequestPriorityToSpdyPriority(HIGHEST, SPDY2)); - EXPECT_EQ(1, ConvertRequestPriorityToSpdyPriority(MEDIUM, SPDY2)); - EXPECT_EQ(2, ConvertRequestPriorityToSpdyPriority(LOW, SPDY2)); - EXPECT_EQ(2, ConvertRequestPriorityToSpdyPriority(LOWEST, SPDY2)); - EXPECT_EQ(3, ConvertRequestPriorityToSpdyPriority(IDLE, SPDY2)); -} - TEST(SpdyHttpUtilsTest, ConvertRequestPriorityToSpdy3Priority) { EXPECT_EQ(0, ConvertRequestPriorityToSpdyPriority(HIGHEST, SPDY3)); EXPECT_EQ(1, ConvertRequestPriorityToSpdyPriority(MEDIUM, SPDY3)); @@ -27,18 +19,6 @@ EXPECT_EQ(4, ConvertRequestPriorityToSpdyPriority(IDLE, SPDY3)); } -TEST(SpdyHttpUtilsTest, ConvertSpdy2PriorityToRequestPriority) { - EXPECT_EQ(HIGHEST, ConvertSpdyPriorityToRequestPriority(0, SPDY2)); - EXPECT_EQ(MEDIUM, ConvertSpdyPriorityToRequestPriority(1, SPDY2)); - EXPECT_EQ(LOW, ConvertSpdyPriorityToRequestPriority(2, SPDY2)); - EXPECT_EQ(IDLE, ConvertSpdyPriorityToRequestPriority(3, SPDY2)); - // These are invalid values, but we should still handle them - // gracefully. - for (int i = 4; i < kuint8max; ++i) { - EXPECT_EQ(IDLE, ConvertSpdyPriorityToRequestPriority(i, SPDY2)); - } -} - TEST(SpdyHttpUtilsTest, ConvertSpdy3PriorityToRequestPriority) { EXPECT_EQ(HIGHEST, ConvertSpdyPriorityToRequestPriority(0, SPDY3)); EXPECT_EQ(MEDIUM, ConvertSpdyPriorityToRequestPriority(1, SPDY3));
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index edb39e9..3836fd3 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -58,7 +58,7 @@ struct SpdyNetworkTransactionTestParams { SpdyNetworkTransactionTestParams() - : protocol(kProtoSPDY3), + : protocol(kProtoSPDY31), ssl_type(SPDYNPN) {} SpdyNetworkTransactionTestParams( @@ -717,12 +717,6 @@ Spdy, SpdyNetworkTransactionTest, ::testing::Values( - SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNOSSL), - SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYSSL), - SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNPN), - SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNOSSL), - SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYSSL), - SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN), SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL), SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL), SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN), @@ -5843,9 +5837,6 @@ // limitations as described above and it's not deterministic, tests may // fail under specific circumstances. TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) { - if (GetParam().protocol < kProtoSPDY3) - return; - static int kFrameCount = 2; scoped_ptr<std::string> content( new std::string(kMaxSpdyFrameChunkSize, 'a')); @@ -5934,9 +5925,6 @@ // Test that received data frames and sent WINDOW_UPDATE frames change // the recv_window_size_ correctly. TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) { - if (GetParam().protocol < kProtoSPDY3) - return; - // Amount of body required to trigger a sent window update. const size_t kTargetSize = kSpdyStreamInitialWindowSize / 2 + 1; @@ -6016,9 +6004,6 @@ // Test that WINDOW_UPDATE frame causing overflow is handled correctly. TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) { - if (GetParam().protocol < kProtoSPDY3) - return; - // Number of full frames we hope to write (but will not, used to // set content-length header correctly) static int kFrameCount = 3; @@ -6098,9 +6083,6 @@ // After that, next read is artifically enforced, which causes a // WINDOW_UPDATE to be read and I/O process resumes. TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) { - if (GetParam().protocol < kProtoSPDY3) - return; - // Number of frames we need to send to zero out the window size: data // frames plus SYN_STREAM plus the last data frame; also we need another // data frame that we will send once the WINDOW_UPDATE is received, @@ -6212,9 +6194,6 @@ // Test we correctly handle the case where the SETTINGS frame results in // unstalling the send window. TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) { - if (GetParam().protocol < kProtoSPDY3) - return; - // Number of frames we need to send to zero out the window size: data // frames plus SYN_STREAM plus the last data frame; also we need another // data frame that we will send once the SETTING is received, therefore +3. @@ -6333,9 +6312,6 @@ // Test we correctly handle the case where the SETTINGS frame results in a // negative send window size. TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) { - if (GetParam().protocol < kProtoSPDY3) - return; - // Number of frames we need to send to zero out the window size: data // frames plus SYN_STREAM plus the last data frame; also we need another // data frame that we will send once the SETTING is received, therefore +3. @@ -6390,10 +6366,7 @@ spdy_util_.ConstructSpdyWindowUpdate(1, kSpdyStreamInitialWindowSize)); reads.push_back(CreateMockRead(*settings_frame_small, i++)); - - if (GetParam().protocol >= kProtoSPDY3) - reads.push_back(CreateMockRead(*session_window_update_init_size, i++)); - + reads.push_back(CreateMockRead(*session_window_update_init_size, i++)); reads.push_back(CreateMockRead(*window_update_init_size, i++)); scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); @@ -6557,10 +6530,7 @@ INSTANTIATE_TEST_CASE_P( Spdy, SpdyNetworkTransactionNoTLSUsageCheckTest, - ::testing::Values(SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, - SPDYNPN), - SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN), - SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN))); + ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN))); TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSVersionTooOld) { scoped_ptr<SSLSocketDataProvider> ssl_provider(
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc index ba5d867..a707ef4 100644 --- a/net/spdy/spdy_proxy_client_socket_unittest.cc +++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -142,8 +142,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, SpdyProxyClientSocketTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); SpdyProxyClientSocketTest::SpdyProxyClientSocketTest() : spdy_util_(GetParam()),
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 08d838a..1c9abce 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -271,6 +271,14 @@ return dict; } +base::Value* NetLogSpdyAdoptedPushStreamCallback( + SpdyStreamId stream_id, const GURL* url, NetLog::LogLevel log_level) { + base::DictionaryValue* dict = new base::DictionaryValue(); + dict->SetInteger("stream_id", stream_id); + dict->SetString("url", url->spec()); + return dict; +} + // Helper function to return the total size of an array of objects // with .size() member functions. template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) { @@ -1963,7 +1971,9 @@ return base::WeakPtr<SpdyStream>(); } - net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM); + net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM, + base::Bind(&NetLogSpdyAdoptedPushStreamCallback, + active_it->second.stream->stream_id(), &url)); used_push_streams.Increment(); return active_it->second.stream->GetWeakPtr(); }
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc index fc38cc2..9d5e48c 100644 --- a/net/spdy/spdy_session_pool_unittest.cc +++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -51,8 +51,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, SpdySessionPoolTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); // A delegate that opens a new session when it is closed. class SessionOpeningDelegate : public SpdyStream::Delegate {
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index 02e0c74..6ec3383 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc
@@ -181,8 +181,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, SpdySessionTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); // Try to create a SPDY session that will fail during // initialization. Nothing should blow up. @@ -1798,10 +1797,6 @@ data.RunFor(1); // Regression test of compression performance under the request fixture. switch (spdy_util_.spdy_version()) { - case SPDY2: - histogram_tester.ExpectBucketCount( - "Net.SpdySynStreamCompressionPercentage", 0, 1); - break; case SPDY3: histogram_tester.ExpectBucketCount( "Net.SpdySynStreamCompressionPercentage", 30, 1); @@ -3084,22 +3079,12 @@ EXPECT_EQ(spdy_util_.spdy_version(), session->buffered_spdy_framer_->protocol_version()); - if (GetParam() == kProtoDeprecatedSPDY2) { - EXPECT_EQ(SpdySession::FLOW_CONTROL_NONE, session->flow_control_state()); - EXPECT_EQ(0, session->session_send_window_size_); - EXPECT_EQ(0, session->session_recv_window_size_); - } else if (GetParam() == kProtoSPDY3) { - EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM, session->flow_control_state()); - EXPECT_EQ(0, session->session_send_window_size_); - EXPECT_EQ(0, session->session_recv_window_size_); - } else { - EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, - session->flow_control_state()); - EXPECT_EQ(kSpdySessionInitialWindowSize, - session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize, - session->session_recv_window_size_); - } + EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, + session->flow_control_state()); + EXPECT_EQ(kSpdySessionInitialWindowSize, + session->session_send_window_size_); + EXPECT_EQ(kSpdySessionInitialWindowSize, + session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); } @@ -3455,9 +3440,6 @@ // The tests below are only for SPDY/3 and above. TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) { - if (GetParam() < kProtoSPDY3) - return; - // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE // gets sent. SettingsMap new_settings;
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc index 96153bf..e8915bb 100644 --- a/net/spdy/spdy_stream_unittest.cc +++ b/net/spdy/spdy_stream_unittest.cc
@@ -110,8 +110,7 @@ INSTANTIATE_TEST_CASE_P( NextProto, SpdyStreamTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); + testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); TEST_P(SpdyStreamTest, SendDataAfterOpen) { GURL url(kStreamUrl); @@ -717,9 +716,6 @@ // to overflow an int32. The SpdyStream should handle that case // gracefully. TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) { - if (spdy_util_.protocol() < kProtoSPDY3) - return; - session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); @@ -877,17 +873,11 @@ } TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) { - if (spdy_util_.protocol() < kProtoSPDY3) - return; - RunResumeAfterUnstallRequestResponseTest( base::Bind(&IncreaseStreamSendWindowSize)); } TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) { - if (spdy_util_.protocol() < kProtoSPDY3) - return; - RunResumeAfterUnstallRequestResponseTest( base::Bind(&AdjustStreamSendWindowSize)); } @@ -972,17 +962,11 @@ } TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) { - if (spdy_util_.protocol() < kProtoSPDY3) - return; - RunResumeAfterUnstallBidirectionalTest( base::Bind(&IncreaseStreamSendWindowSize)); } TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) { - if (spdy_util_.protocol() < kProtoSPDY3) - return; - RunResumeAfterUnstallBidirectionalTest( base::Bind(&AdjustStreamSendWindowSize)); }
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 801d67d..9543e64 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc
@@ -54,8 +54,6 @@ NextProtoVector SpdyNextProtos() { NextProtoVector next_protos; next_protos.push_back(kProtoHTTP11); - next_protos.push_back(kProtoDeprecatedSPDY2); - next_protos.push_back(kProtoSPDY3); next_protos.push_back(kProtoSPDY31); next_protos.push_back(kProtoSPDY4_14); next_protos.push_back(kProtoSPDY4_15); @@ -720,15 +718,11 @@ void SpdyTestUtil::AddUrlToHeaderBlock(base::StringPiece url, SpdyHeaderBlock* headers) const { - if (is_spdy2()) { - (*headers)["url"] = url.as_string(); - } else { - std::string scheme, host, path; - ParseUrl(url, &scheme, &host, &path); - (*headers)[GetSchemeKey()] = scheme; - (*headers)[GetHostKey()] = host; - (*headers)[GetPathKey()] = path; - } + std::string scheme, host, path; + ParseUrl(url, &scheme, &host, &path); + (*headers)[GetSchemeKey()] = scheme; + (*headers)[GetHostKey()] = host; + (*headers)[GetPathKey()] = path; } scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlock( @@ -739,8 +733,6 @@ scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlockForProxy( base::StringPiece url) const { scoped_ptr<SpdyHeaderBlock> headers(ConstructGetHeaderBlock(url)); - if (is_spdy2()) - (*headers)[GetPathKey()] = url.data(); return headers.Pass(); } @@ -963,8 +955,7 @@ bool direct) const { SpdyHeaderBlock block; block[GetMethodKey()] = "GET"; - block[GetPathKey()] = - (is_spdy2() && !direct) ? "http://www.google.com/" : "/"; + block[GetPathKey()] = "/"; block[GetHostKey()] = "www.google.com"; block[GetSchemeKey()] = "http"; MaybeAddVersionHeader(&block); @@ -1259,16 +1250,14 @@ } const char* SpdyTestUtil::GetMethodKey() const { - return is_spdy2() ? "method" : ":method"; + return ":method"; } const char* SpdyTestUtil::GetStatusKey() const { - return is_spdy2() ? "status" : ":status"; + return ":status"; } const char* SpdyTestUtil::GetHostKey() const { - if (protocol_ < kProtoSPDY3) - return "host"; if (protocol_ < kProtoSPDY4MinimumVersion) return ":host"; else @@ -1276,15 +1265,15 @@ } const char* SpdyTestUtil::GetSchemeKey() const { - return is_spdy2() ? "scheme" : ":scheme"; + return ":scheme"; } const char* SpdyTestUtil::GetVersionKey() const { - return is_spdy2() ? "version" : ":version"; + return ":version"; } const char* SpdyTestUtil::GetPathKey() const { - return is_spdy2() ? "url" : ":path"; + return ":path"; } scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructHeaderBlock(
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index b08657c..0ee59d4 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h
@@ -551,7 +551,6 @@ NextProto protocol() const { return protocol_; } SpdyMajorVersion spdy_version() const { return spdy_version_; } - bool is_spdy2() const { return protocol_ < kProtoSPDY3; } bool include_version_header() const { return protocol_ < kProtoSPDY4MinimumVersion; }
diff --git a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java index 66a9bd9..6121a2a 100644 --- a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java +++ b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
@@ -86,8 +86,8 @@ mIsRedirect = isRedirect; mIsNotFound = isNotFound; mResponseData = responseData; - mResponseHeaders = responseHeaders == null ? - new ArrayList<Pair<String, String>>() : responseHeaders; + mResponseHeaders = responseHeaders == null + ? new ArrayList<Pair<String, String>>() : responseHeaders; mResponseAction = responseAction; } } @@ -534,30 +534,30 @@ * single self-generated key. The subject name is "Test Server". */ private static final String SERVER_KEYS_BKS = - "AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41" + - "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" + - "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" + - "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw" + - "MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" + - "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl" + - "cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy" + - "DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV" + - "zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG" + - "9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU" + - "hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV" + - "yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx" + - "4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR" + - "MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN" + - "vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs" + - "P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck" + - "MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM" + - "J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI" + - "rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f" + - "V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx" + - "OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt" + - "bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw" + - "1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" + - "k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw="; + "AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41" + + "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" + + "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" + + "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw" + + "MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" + + "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl" + + "cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy" + + "DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV" + + "zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG" + + "9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU" + + "hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV" + + "yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx" + + "4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR" + + "MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN" + + "vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs" + + "P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck" + + "MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM" + + "J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI" + + "rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f" + + "V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx" + + "OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt" + + "bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw" + + "1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" + + "k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw="; private static final String PASSWORD = "android";
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc index 7ac764f..97b5d84 100644 --- a/net/test/embedded_test_server/embedded_test_server.cc +++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -115,7 +115,7 @@ } EmbeddedTestServer::EmbeddedTestServer() - : port_(-1), + : port_(0), weak_factory_(this) { DCHECK(thread_checker_.CalledOnValidThread()); }
diff --git a/net/test/embedded_test_server/embedded_test_server.h b/net/test/embedded_test_server/embedded_test_server.h index 24ff8d7..586e1f4 100644 --- a/net/test/embedded_test_server/embedded_test_server.h +++ b/net/test/embedded_test_server/embedded_test_server.h
@@ -136,7 +136,7 @@ const std::string& relative_url) const; // Returns the port number used by the server. - int port() const { return port_; } + uint16 port() const { return port_; } // Registers request handler which serves files from |directory|. // For instance, a request to "/foo.html" is served by "foo.html" under @@ -188,7 +188,7 @@ scoped_ptr<base::Thread> io_thread_; scoped_ptr<HttpListenSocket> listen_socket_; - int port_; + uint16 port_; GURL base_url_; // Owns the HttpConnection objects.
diff --git a/net/test/embedded_test_server/embedded_test_server_unittest.cc b/net/test/embedded_test_server/embedded_test_server_unittest.cc index 28d909e..efa4b0c 100644 --- a/net/test/embedded_test_server/embedded_test_server_unittest.cc +++ b/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -112,12 +112,12 @@ }; TEST_F(EmbeddedTestServerTest, GetBaseURL) { - EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/", server_->port()), + EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%u/", server_->port()), server_->base_url().spec()); } TEST_F(EmbeddedTestServerTest, GetURL) { - EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/path?query=foo", + EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%u/path?query=foo", server_->port()), server_->GetURL("/path?query=foo").spec()); }
diff --git a/net/tools/dump_cache/cache_dumper.cc b/net/tools/dump_cache/cache_dumper.cc index 0ce46a9..99e3dcd 100644 --- a/net/tools/dump_cache/cache_dumper.cc +++ b/net/tools/dump_cache/cache_dumper.cc
@@ -45,7 +45,6 @@ #ifdef WIN32_LARGE_FILENAME_SUPPORT // Due to large paths on windows, it can't simply do a // CreateDirectory("a/b/c"). Instead, create each subdirectory manually. - bool rv = false; std::wstring::size_type pos(0); std::wstring backslash(L"\\");
diff --git a/net/tools/flip_server/spdy_interface_test.cc b/net/tools/flip_server/spdy_interface_test.cc index 09909e2..d845438 100644 --- a/net/tools/flip_server/spdy_interface_test.cc +++ b/net/tools/flip_server/spdy_interface_test.cc
@@ -206,8 +206,8 @@ INSTANTIATE_TEST_CASE_P(SpdySMProxyTest, SpdySMProxyTest, - Values(SPDY2, SPDY3, SPDY4)); -INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(SPDY2)); + Values(SPDY3, SPDY4)); +INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(SPDY4)); TEST_P(SpdySMProxyTest, InitSMConnection) { { @@ -218,113 +218,7 @@ NULL, NULL, epoll_server_.get(), -1, "", "", "", false); } -TEST_P(SpdySMProxyTest, OnSynStream_SPDY2) { - if (GetParam() != SPDY2) { - // This test case is for SPDY2. - return; - } - BufferedSpdyFramerVisitorInterface* visitor = interface_.get(); - scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface); - uint32 stream_id = 92; - uint32 associated_id = 43; - std::string expected = "GET /path HTTP/1.0\r\n" - "Host: 127.0.0.1\r\n" - "hoge: fuga\r\n\r\n"; - SpdyHeaderBlock block; - block["method"] = "GET"; - block["url"] = "/path"; - block["scheme"] = "http"; - block["version"] = "HTTP/1.0"; - block["hoge"] = "fuga"; - StringSaver saver; - { - InSequence s; - EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _)) - .WillOnce(Return(mock_interface.get())); - EXPECT_CALL(*mock_interface, SetStreamID(stream_id)); - EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)) - .WillOnce(DoAll(SaveArg<0>(&saver.data), - SaveArg<1>(&saver.size), - InvokeWithoutArgs(&saver, &StringSaver::Save), - Return(0))); - } - visitor->OnSynStream(stream_id, associated_id, 0, false, false, block); - ASSERT_EQ(expected, saver.string); -} - -TEST_P(SpdySMProxyTest, OnSynStream) { - if (GetParam() == SPDY2) { - // This test case is not for SPDY2. - return; - } - BufferedSpdyFramerVisitorInterface* visitor = interface_.get(); - scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface); - uint32 stream_id = 92; - uint32 associated_id = 43; - std::string expected = "GET /path HTTP/1.1\r\n" - "Host: 127.0.0.1\r\n" - "foo: bar\r\n\r\n"; - SpdyHeaderBlock block; - block[":method"] = "GET"; - block[":host"] = "www.example.com"; - block[":path"] = "/path"; - block[":scheme"] = "http"; - block["foo"] = "bar"; - StringSaver saver; - { - InSequence s; - EXPECT_CALL(*interface_, - FindOrMakeNewSMConnectionInterface(_, _)) - .WillOnce(Return(mock_interface.get())); - EXPECT_CALL(*mock_interface, SetStreamID(stream_id)); - EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)) - .WillOnce(DoAll(SaveArg<0>(&saver.data), - SaveArg<1>(&saver.size), - InvokeWithoutArgs(&saver, &StringSaver::Save), - Return(0))); - } - visitor->OnSynStream(stream_id, associated_id, 0, false, false, block); - ASSERT_EQ(expected, saver.string); -} - -TEST_P(SpdySMProxyTest, OnStreamFrameData_SPDY2) { - if (GetParam() != SPDY2) { - // This test case is for SPDY2. - return; - } - BufferedSpdyFramerVisitorInterface* visitor = interface_.get(); - scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface); - uint32 stream_id = 92; - uint32 associated_id = 43; - SpdyHeaderBlock block; - testing::MockFunction<void(int)> checkpoint; // NOLINT - - scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12, false)); - block["method"] = "GET"; - block["url"] = "http://www.example.com/path"; - block["scheme"] = "http"; - block["version"] = "HTTP/1.0"; - { - InSequence s; - EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _)) - .WillOnce(Return(mock_interface.get())); - EXPECT_CALL(*mock_interface, SetStreamID(stream_id)); - EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1); - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(*mock_interface, - ProcessWriteInput(frame->data(), frame->size())).Times(1); - } - - visitor->OnSynStream(stream_id, associated_id, 0, false, false, block); - checkpoint.Call(0); - visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true); -} - TEST_P(SpdySMProxyTest, OnStreamFrameData) { - if (GetParam() == SPDY2) { - // This test case is not for SPDY2. - return; - } BufferedSpdyFramerVisitorInterface* visitor = interface_.get(); scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface); uint32 stream_id = 92; @@ -407,14 +301,14 @@ TEST_P(SpdySMProxyTest, CreateFramer) { interface_->ResetForNewConnection(); - interface_->CreateFramer(SPDY2); - ASSERT_TRUE(interface_->spdy_framer() != NULL); - ASSERT_EQ(interface_->spdy_version(), SPDY2); - - interface_->ResetForNewConnection(); interface_->CreateFramer(SPDY3); ASSERT_TRUE(interface_->spdy_framer() != NULL); ASSERT_EQ(interface_->spdy_version(), SPDY3); + + interface_->ResetForNewConnection(); + interface_->CreateFramer(SPDY4); + ASSERT_TRUE(interface_->spdy_framer() != NULL); + ASSERT_EQ(interface_->spdy_version(), SPDY4); } TEST_P(SpdySMProxyTest, PostAcceptHook) { @@ -455,61 +349,7 @@ ASSERT_TRUE(HasStream(stream_id)); } -TEST_P(SpdySMProxyTest, SendErrorNotFound_SPDY2) { - if (GetParam() != SPDY2) { - // This test is for SPDY2. - return; - } - uint32 stream_id = 82; - SpdyHeaderBlock actual_header_block; - const char* actual_data; - size_t actual_size; - testing::MockFunction<void(int)> checkpoint; // NOLINT - - interface_->SendErrorNotFound(stream_id); - - ASSERT_EQ(2u, connection_->output_list()->size()); - - { - InSequence s; - if (GetParam() < SPDY4) { - EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _)) - .WillOnce(SaveArg<2>(&actual_header_block)); - } else { - EXPECT_CALL(*spdy_framer_visitor_, - OnHeaders(stream_id, false, 0, false, _)) - .WillOnce(SaveArg<4>(&actual_header_block)); - } - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(*spdy_framer_visitor_, - OnDataFrameHeader(stream_id, _, true)); - EXPECT_CALL(*spdy_framer_visitor_, - OnStreamFrameData(stream_id, _, _, false)).Times(1) - .WillOnce(DoAll(SaveArg<1>(&actual_data), - SaveArg<2>(&actual_size))); - EXPECT_CALL(*spdy_framer_visitor_, - OnStreamFrameData(stream_id, NULL, 0, true)).Times(1); - } - - std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin(); - DataFrame* df = *i++; - spdy_framer_->ProcessInput(df->data, df->size); - checkpoint.Call(0); - df = *i++; - spdy_framer_->ProcessInput(df->data, df->size); - - ASSERT_EQ(2, spdy_framer_->frames_received()); - ASSERT_EQ(2u, actual_header_block.size()); - ASSERT_EQ("404 Not Found", actual_header_block["status"]); - ASSERT_EQ("HTTP/1.1", actual_header_block["version"]); - ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size)); -} - TEST_P(SpdySMProxyTest, SendErrorNotFound) { - if (GetParam() == SPDY2) { - // This test is not for SPDY2. - return; - } uint32 stream_id = 82; SpdyHeaderBlock actual_header_block; const char* actual_data; @@ -556,44 +396,7 @@ ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size)); } -TEST_P(SpdySMProxyTest, SendSynStream_SPDY2) { - if (GetParam() != SPDY2) { - // This test is for SPDY2. - return; - } - uint32 stream_id = 82; - BalsaHeaders headers; - SpdyHeaderBlock actual_header_block; - headers.AppendHeader("key1", "value1"); - headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.0"); - - interface_->SendSynStream(stream_id, headers); - - ASSERT_EQ(1u, connection_->output_list()->size()); - std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin(); - DataFrame* df = *i++; - - { - InSequence s; - EXPECT_CALL(*spdy_framer_visitor_, - OnSynStream(stream_id, 0, _, false, false, _)) - .WillOnce(SaveArg<5>(&actual_header_block)); - } - - spdy_framer_->ProcessInput(df->data, df->size); - ASSERT_EQ(1, spdy_framer_->frames_received()); - ASSERT_EQ(4u, actual_header_block.size()); - ASSERT_EQ("GET", actual_header_block["method"]); - ASSERT_EQ("HTTP/1.0", actual_header_block["version"]); - ASSERT_EQ("/path", actual_header_block["url"]); - ASSERT_EQ("value1", actual_header_block["key1"]); -} - TEST_P(SpdySMProxyTest, SendSynStream) { - if (GetParam() == SPDY2) { - // This test is not for SPDY2. - return; - } uint32 stream_id = 82; BalsaHeaders headers; SpdyHeaderBlock actual_header_block; @@ -624,48 +427,7 @@ ASSERT_EQ("value1", actual_header_block["key1"]); } -TEST_P(SpdySMProxyTest, SendSynReply_SPDY2) { - if (GetParam() != SPDY2) { - // This test is for SPDY2. - return; - } - uint32 stream_id = 82; - BalsaHeaders headers; - SpdyHeaderBlock actual_header_block; - headers.AppendHeader("key1", "value1"); - headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK"); - - interface_->SendSynReply(stream_id, headers); - - ASSERT_EQ(1u, connection_->output_list()->size()); - std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin(); - DataFrame* df = *i++; - - { - InSequence s; - if (GetParam() < SPDY4) { - EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _)) - .WillOnce(SaveArg<2>(&actual_header_block)); - } else { - EXPECT_CALL(*spdy_framer_visitor_, - OnHeaders(stream_id, false, 0, false, _)) - .WillOnce(SaveArg<4>(&actual_header_block)); - } - } - - spdy_framer_->ProcessInput(df->data, df->size); - ASSERT_EQ(1, spdy_framer_->frames_received()); - ASSERT_EQ(3u, actual_header_block.size()); - ASSERT_EQ("200 OK", actual_header_block["status"]); - ASSERT_EQ("HTTP/1.1", actual_header_block["version"]); - ASSERT_EQ("value1", actual_header_block["key1"]); -} - TEST_P(SpdySMProxyTest, SendSynReply) { - if (GetParam() == SPDY2) { - // This test is not for SPDY2. - return; - } uint32 stream_id = 82; BalsaHeaders headers; SpdyHeaderBlock actual_header_block; @@ -763,58 +525,6 @@ ASSERT_EQ("c", StringPiece(actual_data, actual_size)); } -TEST_P(SpdySMProxyTest, SendEOF_SPDY2) { - // This test is for SPDY2. - if (GetParam() != SPDY2) { - return; - } - - uint32 stream_id = 82; - // SPDY2 data frame - char empty_data_frame[] = {'\0', '\0', '\0', '\x52', '\x1', '\0', '\0', '\0'}; - MemCacheIter mci; - mci.stream_id = stream_id; - - { - BalsaHeaders headers; - std::string filename = "foobar"; - memory_cache_->InsertFile(&headers, filename, ""); - mci.file_data = memory_cache_->GetFileData(filename); - } - - interface_->AddToOutputOrder(mci); - ASSERT_TRUE(HasStream(stream_id)); - interface_->SendEOF(stream_id); - ASSERT_FALSE(HasStream(stream_id)); - - ASSERT_EQ(1u, connection_->output_list()->size()); - std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin(); - DataFrame* df = *i++; - ASSERT_EQ(StringPiece(empty_data_frame, sizeof(empty_data_frame)), - StringPiece(df->data, df->size)); -} - -TEST_P(SpdySMProxyTest, SendEmptyDataFrame_SPDY2) { - // This test is for SPDY2. - if (GetParam() != SPDY2) { - return; - } - - uint32 stream_id = 133; - SpdyDataFlags flags = DATA_FLAG_NONE; - // SPDY2 data frame - char expected[] = {'\0', '\0', '\0', '\x85', '\0', '\0', '\0', '\0'}; - - interface_->SendDataFrame(stream_id, "hello", 0, flags, true); - - ASSERT_EQ(1u, connection_->output_list()->size()); - std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin(); - DataFrame* df = *i++; - - ASSERT_EQ(StringPiece(expected, sizeof(expected)), - StringPiece(df->data, df->size)); -} - TEST_P(SpdySMServerTest, OnSynStream) { BufferedSpdyFramerVisitorInterface* visitor = interface_.get(); uint32 stream_id = 82;
diff --git a/net/tools/gdig/gdig.cc b/net/tools/gdig/gdig.cc index 179ab78..0f8c1fe 100644 --- a/net/tools/gdig/gdig.cc +++ b/net/tools/gdig/gdig.cc
@@ -6,6 +6,7 @@ #include <string> #include "base/at_exit.h" +#include "base/basictypes.h" #include "base/bind.h" #include "base/cancelable_callback.h" #include "base/command_line.h" @@ -53,7 +54,7 @@ if (!net::ParseIPLiteralToNumber(ip, &ip_number)) return false; - *ip_end_point = net::IPEndPoint(ip_number, port); + *ip_end_point = net::IPEndPoint(ip_number, static_cast<uint16>(port)); return true; } @@ -90,7 +91,7 @@ ++i) { const DnsHostsKey& key = i->first; std::string host_name = key.first; - output.append(IPEndPoint(i->second, -1).ToStringWithoutPort()); + output.append(IPEndPoint(i->second, 0).ToStringWithoutPort()); output.append(" ").append(host_name).append("\n"); } return output;
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 33f30fc..dcc9345 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -221,7 +221,7 @@ "HTTP/1.1", "200", "OK", kBarResponseBody); } - virtual ~EndToEndTest() { + ~EndToEndTest() override { // TODO(rtenneti): port RecycleUnusedPort if needed. // RecycleUnusedPort(server_address_.port()); QuicInMemoryCachePeer::ResetForTests();
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index 5b5c415..496211f 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc
@@ -46,6 +46,8 @@ session_->InitializeSession( QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED), &crypto_config_); + // Advance the time, because timers do not like uninitialized times. + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); } void CompleteCryptoHandshake() {
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc index 45c1379..9db2365 100644 --- a/net/tools/quic/quic_server_session.cc +++ b/net/tools/quic/quic_server_session.cc
@@ -38,14 +38,29 @@ void QuicServerSession::OnConfigNegotiated() { QuicSession::OnConfigNegotiated(); - if (!FLAGS_enable_quic_fec || - !config()->HasReceivedConnectionOptions() || - !net::ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) { + + if (!config()->HasReceivedConnectionOptions()) { return; } - // kFHDR config maps to FEC protection always for headers stream. - // TODO(jri): Add crypto stream in addition to headers for kHDR. - headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS); + + // If the client has provided a bandwidth estimate from the same serving + // region, then pass it to the sent packet manager in preparation for possible + // bandwidth resumption. + const CachedNetworkParameters* cached_network_params = + crypto_stream_->previous_cached_network_params(); + if (FLAGS_quic_enable_bandwidth_resumption_experiment && + cached_network_params != nullptr && + ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE) && + cached_network_params->serving_region() == serving_region_) { + connection()->ResumeConnectionState(*cached_network_params); + } + + if (FLAGS_enable_quic_fec && + ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) { + // kFHDR config maps to FEC protection always for headers stream. + // TODO(jri): Add crypto stream in addition to headers for kHDR. + headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS); + } } void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc index 6a17f53..b0ed5d1 100644 --- a/net/tools/quic/quic_server_session_test.cc +++ b/net/tools/quic/quic_server_session_test.cc
@@ -292,7 +292,7 @@ explicit MockQuicCryptoServerStream( const QuicCryptoServerConfig& crypto_config, QuicSession* session) : QuicCryptoServerStream(crypto_config, session) {} - virtual ~MockQuicCryptoServerStream() {} + ~MockQuicCryptoServerStream() override {} MOCK_METHOD1(SendServerConfigUpdate, void(const CachedNetworkParameters* cached_network_parameters)); @@ -383,6 +383,46 @@ session_->OnCongestionWindowChange(now); } +TEST_P(QuicServerSessionTest, BandwidthResumptionExperiment) { + ValueRestore<bool> old_flag( + &FLAGS_quic_enable_bandwidth_resumption_experiment, true); + + // Test that if a client provides a CachedNetworkParameters with the same + // serving region as the current server, that this data is passed down to the + // send algorithm. + + // Client has sent kBWRE connection option to trigger bandwidth resumption. + QuicTagVector copt; + copt.push_back(kBWRE); + QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); + + const string kTestServingRegion = "a serving region"; + session_->set_serving_region(kTestServingRegion); + + QuicCryptoServerStream* crypto_stream = + static_cast<QuicCryptoServerStream*>( + QuicSessionPeer::GetCryptoStream(session_.get())); + + // No effect if no CachedNetworkParameters provided. + EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(0); + session_->OnConfigNegotiated(); + + // No effect if CachedNetworkParameters provided, but different serving + // regions. + CachedNetworkParameters cached_network_params; + cached_network_params.set_bandwidth_estimate_bytes_per_second(1); + cached_network_params.set_serving_region("different serving region"); + crypto_stream->set_previous_cached_network_params(cached_network_params); + EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(0); + session_->OnConfigNegotiated(); + + // Same serving region results in CachedNetworkParameters being stored. + cached_network_params.set_serving_region(kTestServingRegion); + crypto_stream->set_previous_cached_network_params(cached_network_params); + EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(1); + session_->OnConfigNegotiated(); +} + } // namespace } // namespace test } // namespace tools
diff --git a/net/tools/quic/quic_spdy_server_stream_test.cc b/net/tools/quic/quic_spdy_server_stream_test.cc index 4f5484a..8a3600c 100644 --- a/net/tools/quic/quic_spdy_server_stream_test.cc +++ b/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -97,7 +97,7 @@ QuicInMemoryCachePeer::ResetForTests(); } - virtual void SetUp() override { + void SetUp() override { QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance(); BalsaHeaders request_headers, response_headers;
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc index 05c3954..4e5d7c3 100644 --- a/net/tools/quic/quic_time_wait_list_manager_test.cc +++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -95,9 +95,9 @@ client_address_(net::test::TestPeerIPAddress(), kTestPort), writer_is_blocked_(false) {} - virtual ~QuicTimeWaitListManagerTest() override {} + ~QuicTimeWaitListManagerTest() override {} - virtual void SetUp() override { + void SetUp() override { EXPECT_CALL(writer_, IsWriteBlocked()) .WillRepeatedly(ReturnPointee(&writer_is_blocked_)); EXPECT_CALL(writer_, IsWriteBlockedDataBuffered())
diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.h b/net/tools/quic/test_tools/mock_quic_dispatcher.h index df32ce4..81f1004 100644 --- a/net/tools/quic/test_tools/mock_quic_dispatcher.h +++ b/net/tools/quic/test_tools/mock_quic_dispatcher.h
@@ -24,7 +24,7 @@ PacketWriterFactory* packet_writer_factory, EpollServer* eps); - virtual ~MockQuicDispatcher(); + ~MockQuicDispatcher() override; MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address, const IPEndPoint& client_address,
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h index 9db9fb5..e1220cb 100644 --- a/net/tools/quic/test_tools/quic_test_utils.h +++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -10,6 +10,7 @@ #include <string> #include "base/strings/string_piece.h" +#include "net/quic/crypto/cached_network_parameters.h" #include "net/quic/quic_connection.h" #include "net/quic/quic_packet_writer.h" #include "net/quic/quic_session.h" @@ -94,6 +95,8 @@ MOCK_METHOD0(OnCanWrite, void()); MOCK_CONST_METHOD0(HasPendingWrites, bool()); + MOCK_METHOD1(ResumeConnectionState, void(const CachedNetworkParameters&)); + void ReallyProcessUdpPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, const QuicEncryptedPacket& packet) {
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc index 83689c7..8282596 100644 --- a/net/udp/udp_socket_unittest.cc +++ b/net/udp/udp_socket_unittest.cc
@@ -119,7 +119,7 @@ }; // Creates and address from an ip/port and returns it in |address|. -void CreateUDPAddress(std::string ip_str, int port, IPEndPoint* address) { +void CreateUDPAddress(std::string ip_str, uint16 port, IPEndPoint* address) { IPAddressNumber ip_number; bool rv = ParseIPLiteralToNumber(ip_str, &ip_number); if (!rv) @@ -128,7 +128,7 @@ } TEST_F(UDPSocketTest, Connect) { - const int kPort = 9999; + const uint16 kPort = 9999; std::string simple_message("hello world!"); // Setup the server to listen. @@ -216,7 +216,7 @@ #else TEST_F(UDPSocketTest, Broadcast) { #endif - const int kPort = 9999; + const uint16 kPort = 9999; std::string first_message("first message"), second_message("second message"); IPEndPoint broadcast_address; @@ -369,8 +369,8 @@ // not bind the client's reads to only be from that endpoint, and that we need // to always use recvfrom() to disambiguate. TEST_F(UDPSocketTest, VerifyConnectBindsAddr) { - const int kPort1 = 9999; - const int kPort2 = 10000; + const uint16 kPort1 = 9999; + const uint16 kPort2 = 10000; std::string simple_message("hello world!"); std::string foreign_message("BAD MESSAGE TO GET!!"); @@ -538,7 +538,7 @@ #endif // defined(OS_ANDROID) TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) { - const int kPort = 9999; + const uint16 kPort = 9999; const char* const kGroup = "237.132.100.17"; IPEndPoint bind_address; @@ -562,7 +562,7 @@ } TEST_F(UDPSocketTest, MulticastOptions) { - const int kPort = 9999; + const uint16 kPort = 9999; IPEndPoint bind_address; CreateUDPAddress("0.0.0.0", kPort, &bind_address);
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc index 11c731f..7be97e8 100644 --- a/net/udp/udp_socket_win.cc +++ b/net/udp/udp_socket_win.cc
@@ -6,6 +6,7 @@ #include <mstcpip.h> +#include "base/basictypes.h" #include "base/callback.h" #include "base/lazy_instance.h" #include "base/logging.h" @@ -808,8 +809,8 @@ DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); for (int i = 0; i < kBindRetries; ++i) { - int rv = DoBind(IPEndPoint(address, - rand_int_cb_.Run(kPortStart, kPortEnd))); + int rv = DoBind(IPEndPoint( + address, static_cast<uint16>(rand_int_cb_.Run(kPortStart, kPortEnd)))); if (rv == OK || rv != ERR_ADDRESS_IN_USE) return rv; }
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index a2ce07e..c61a14b 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -650,12 +650,8 @@ response_info_.was_cached = false; - // If the referrer is secure, but the requested URL is not, the referrer - // policy should be something non-default. If you hit this, please file a - // bug. - if (referrer_policy_ == - CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE && - GURL(referrer_).SchemeIsSecure() && !url().SchemeIsSecure()) { + if (GURL(referrer_) != URLRequestJob::ComputeReferrerForRedirect( + referrer_policy_, referrer_, url())) { if (!network_delegate_ || !network_delegate_->CancelURLRequestWithPolicyViolatingReferrerHeader( *this, url(), GURL(referrer_))) {
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index 6117419..af972bd 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h
@@ -94,14 +94,22 @@ // referrer header might be cleared, if the protocol changes from HTTPS to // HTTP. This is the default behavior of URLRequest, corresponding to // CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE. Alternatively, the - // referrer policy can be set to never change the referrer header. This - // behavior corresponds to NEVER_CLEAR_REFERRER. Embedders will want to use - // NEVER_CLEAR_REFERRER when implementing the meta-referrer support - // (http://wiki.whatwg.org/wiki/Meta_referrer) and sending requests with a - // non-default referrer policy. Only the default referrer policy requires - // the referrer to be cleared on transitions from HTTPS to HTTP. + // referrer policy can be set to strip the referrer down to an origin upon + // cross-origin navigation (ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN), or + // never change the referrer header (NEVER_CLEAR_REFERRER). Embedders will + // want to use these options when implementing referrer policy support + // (https://w3c.github.io/webappsec/specs/referrer-policy/). + // + // REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN is a slight variant + // on CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE: If the request + // downgrades from HTTPS to HTTP, the referrer will be cleared. If the request + // transitions cross-origin (but does not downgrade), the referrer's + // granularity will be reduced (currently stripped down to an origin rather + // than a full URL). Same-origin requests will send the full referrer. enum ReferrerPolicy { CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN, + ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN, NEVER_CLEAR_REFERRER, };
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc index 41420d5..838aa7b 100644 --- a/net/url_request/url_request_context_builder.cc +++ b/net/url_request/url_request_context_builder.cc
@@ -122,11 +122,6 @@ return true; } - int OnBeforeSocketStreamConnect(SocketStream* stream, - const CompletionCallback& callback) override { - return OK; - } - DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate); };
diff --git a/net/url_request/url_request_data_job.cc b/net/url_request/url_request_data_job.cc index 879b8ba..e074646 100644 --- a/net/url_request/url_request_data_job.cc +++ b/net/url_request/url_request_data_job.cc
@@ -6,7 +6,6 @@ #include "net/url_request/url_request_data_job.h" -#include "base/profiler/scoped_tracker.h" #include "net/base/data_url.h" #include "net/base/net_errors.h" #include "net/http/http_response_headers.h" @@ -53,10 +52,6 @@ std::string* charset, std::string* data, const CompletionCallback& callback) const { - // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION("422489 URLRequestDataJob::GetData")); - // Check if data URL is valid. If not, don't bother to try to extract data. // Otherwise, parse the data from the data URL. const GURL& url = request_->url();
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 33a5088..acf1d07 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -66,17 +66,13 @@ base::Time GetRequestTime() const override; bool IsCachedContent() const override; bool IsDownload() const override; - bool SdchResponseExpected() const override; + SdchManager::DictionarySet* SdchDictionariesAdvertised() const override; int64 GetByteReadCount() const override; int GetResponseCode() const override; const URLRequestContext* GetURLRequestContext() const override; void RecordPacketStats(StatisticSelector statistic) const override; const BoundNetLog& GetNetLog() const override; - // Method to allow us to reset filter context for a response that should have - // been SDCH encoded when there is an update due to an explicit HTTP header. - void ResetSdchResponseToFalse(); - private: URLRequestHttpJob* job_; @@ -126,13 +122,9 @@ return (job_->request_info_.load_flags & LOAD_IS_DOWNLOAD) != 0; } -void URLRequestHttpJob::HttpFilterContext::ResetSdchResponseToFalse() { - DCHECK(job_->sdch_dictionary_advertised_); - job_->sdch_dictionary_advertised_ = false; -} - -bool URLRequestHttpJob::HttpFilterContext::SdchResponseExpected() const { - return job_->sdch_dictionary_advertised_; +SdchManager::DictionarySet* +URLRequestHttpJob::HttpFilterContext::SdchDictionariesAdvertised() const { + return job_->dictionaries_advertised_.get(); } int64 URLRequestHttpJob::HttpFilterContext::GetByteReadCount() const { @@ -200,7 +192,6 @@ base::Unretained(this))), read_in_progress_(false), throttling_entry_(NULL), - sdch_dictionary_advertised_(false), sdch_test_activated_(false), sdch_test_control_(false), is_cached_content_(false), @@ -273,7 +264,7 @@ // plugin could set a referrer although sending the referrer is inhibited. request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kReferer); - // Our consumer should have made sure that this is a safe referrer. See for + // Our consumer should have made sure that this is a safe referrer. See for // instance WebCore::FrameLoader::HideReferrer. if (referrer.is_valid()) { request_info_.extra_headers.SetHeader(HttpRequestHeaders::kReferer, @@ -330,6 +321,7 @@ ProcessStrictTransportSecurityHeader(); ProcessPublicKeyPinsHeader(); + // Handle the server notification of a new SDCH dictionary. SdchManager* sdch_manager(request()->context()->sdch_manager()); if (sdch_manager) { SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url()); @@ -371,6 +363,24 @@ } } + // Handle the server signalling no SDCH encoding. + if (dictionaries_advertised_) { + // We are wary of proxies that discard or damage SDCH encoding. If a server + // explicitly states that this is not SDCH content, then we can correct our + // assumption that this is an SDCH response, and avoid the need to recover + // as though the content is corrupted (when we discover it is not SDCH + // encoded). + std::string sdch_response_status; + void* iter = NULL; + while (GetResponseHeaders()->EnumerateHeader(&iter, "X-Sdch-Encode", + &sdch_response_status)) { + if (sdch_response_status == "0") { + dictionaries_advertised_.reset(); + break; + } + } + } + // The HTTP transaction may be restarted several times for the purposes // of sending authorization information. Each time it restarts, we get // notified of the headers completion so that we can update the cookie store. @@ -532,34 +542,34 @@ } } } - std::string avail_dictionaries; if (advertise_sdch) { - sdch_manager->GetAvailDictionaryList(request_->url(), - &avail_dictionaries); + dictionaries_advertised_ = + sdch_manager->GetDictionarySet(request_->url()); + } - // The AllowLatencyExperiment() is only true if we've successfully done a - // full SDCH compression recently in this browser session for this host. - // Note that for this path, there might be no applicable dictionaries, - // and hence we can't participate in the experiment. - if (!avail_dictionaries.empty() && - sdch_manager->AllowLatencyExperiment(request_->url())) { - // We are participating in the test (or control), and hence we'll - // eventually record statistics via either SDCH_EXPERIMENT_DECODE or - // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data. - packet_timing_enabled_ = true; - if (base::RandDouble() < .01) { - sdch_test_control_ = true; // 1% probability. - advertise_sdch = false; - } else { - sdch_test_activated_ = true; - } + // The AllowLatencyExperiment() is only true if we've successfully done a + // full SDCH compression recently in this browser session for this host. + // Note that for this path, there might be no applicable dictionaries, + // and hence we can't participate in the experiment. + if (dictionaries_advertised_ && + sdch_manager->AllowLatencyExperiment(request_->url())) { + // We are participating in the test (or control), and hence we'll + // eventually record statistics via either SDCH_EXPERIMENT_DECODE or + // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data. + packet_timing_enabled_ = true; + if (base::RandDouble() < .01) { + sdch_test_control_ = true; // 1% probability. + dictionaries_advertised_.reset(); + advertise_sdch = false; + } else { + sdch_test_activated_ = true; } } // Supply Accept-Encoding headers first so that it is more likely that they - // will be in the first transmitted packet. This can sometimes make it + // will be in the first transmitted packet. This can sometimes make it // easier to filter and analyze the streams to assure that a proxy has not - // damaged these headers. Some proxies deliberately corrupt Accept-Encoding + // damaged these headers. Some proxies deliberately corrupt Accept-Encoding // headers. if (!advertise_sdch) { // Tell the server what compression formats we support (other than SDCH). @@ -569,15 +579,14 @@ // Include SDCH in acceptable list. request_info_.extra_headers.SetHeader( HttpRequestHeaders::kAcceptEncoding, "gzip, deflate, sdch"); - if (!avail_dictionaries.empty()) { + if (dictionaries_advertised_) { request_info_.extra_headers.SetHeader( kAvailDictionaryHeader, - avail_dictionaries); - sdch_dictionary_advertised_ = true; + dictionaries_advertised_->GetDictionaryClientHashList()); // Since we're tagging this transaction as advertising a dictionary, // we'll definitely employ an SDCH filter (or tentative sdch filter) - // when we get a response. When done, we'll record histograms via - // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet + // when we get a response. When done, we'll record histograms via + // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet // arrival times. packet_timing_enabled_ = true; } @@ -1029,7 +1038,7 @@ void URLRequestHttpJob::GetLoadTimingInfo( LoadTimingInfo* load_timing_info) const { // If haven't made it far enough to receive any headers, don't return - // anything. This makes for more consistent behavior in the case of errors. + // anything. This makes for more consistent behavior in the case of errors. if (!transaction_ || receive_headers_end_.is_null()) return; if (transaction_->GetLoadTimingInfo(load_timing_info)) @@ -1072,23 +1081,6 @@ encoding_types.push_back(Filter::ConvertEncodingToType(encoding_type)); } - if (filter_context_->SdchResponseExpected()) { - // We are wary of proxies that discard or damage SDCH encoding. If a server - // explicitly states that this is not SDCH content, then we can correct our - // assumption that this is an SDCH response, and avoid the need to recover - // as though the content is corrupted (when we discover it is not SDCH - // encoded). - std::string sdch_response_status; - iter = NULL; - while (headers->EnumerateHeader(&iter, "X-Sdch-Encode", - &sdch_response_status)) { - if (sdch_response_status == "0") { - filter_context_->ResetSdchResponseToFalse(); - break; - } - } - } - // Even if encoding types are empty, there is a chance that we need to add // some decoding, as some proxies strip encoding completely. In such cases, // we may need to add (for example) SDCH filtering (when the context suggests @@ -1132,7 +1124,7 @@ if (code == -1) return false; - // Check if we need either Proxy or WWW Authentication. This could happen + // Check if we need either Proxy or WWW Authentication. This could happen // because we either provided no auth info, or provided incorrect info. switch (code) { case 407: @@ -1266,7 +1258,7 @@ bool URLRequestHttpJob::ShouldFixMismatchedContentLength(int rv) const { // Some servers send the body compressed, but specify the content length as - // the uncompressed size. Although this violates the HTTP spec we want to + // the uncompressed size. Although this violates the HTTP spec we want to // support it (as IE and FireFox do), but *only* for an exact match. // See http://crbug.com/79694. if (rv == net::ERR_CONTENT_LENGTH_MISMATCH || @@ -1461,7 +1453,7 @@ !prefilter_bytes_read()) // Zero-byte responses aren't useful. return; - // Miniature requests aren't really compressible. Don't count them. + // Miniature requests aren't really compressible. Don't count them. const int kMinSize = 16; if (prefilter_bytes_read() < kMinSize) return; @@ -1478,14 +1470,14 @@ // We want to record how often downloaded resources are compressed. // But, we recognize that different protocols may have different - // properties. So, for each request, we'll put it into one of 3 + // properties. So, for each request, we'll put it into one of 3 // groups: // a) SSL resources // Proxies cannot tamper with compression headers with SSL. // b) Non-SSL, loaded-via-proxy resources // In this case, we know a proxy might have interfered. // c) Non-SSL, loaded-without-proxy resources - // In this case, we know there was no explicit proxy. However, + // In this case, we know there was no explicit proxy. However, // it is possible that a transparent proxy was still interfering. // // For each group, we record the same 3 histograms.
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h index f4bea7e..3a23e8a 100644 --- a/net/url_request/url_request_http_job.h +++ b/net/url_request/url_request_http_job.h
@@ -15,6 +15,7 @@ #include "net/base/auth.h" #include "net/base/completion_callback.h" #include "net/base/net_export.h" +#include "net/base/sdch_manager.h" #include "net/cookies/cookie_store.h" #include "net/filter/filter.h" #include "net/http/http_request_info.h" @@ -32,7 +33,7 @@ class UploadDataStream; class URLRequestContext; -// A URLRequestJob subclass that is built on top of HttpTransaction. It +// A URLRequestJob subclass that is built on top of HttpTransaction. It // provides an implementation for both HTTP and HTTPS. class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob { public: @@ -194,17 +195,15 @@ scoped_ptr<HttpTransaction> transaction_; // This is used to supervise traffic and enforce exponential - // back-off. May be NULL. + // back-off. May be NULL. scoped_refptr<URLRequestThrottlerEntryInterface> throttling_entry_; - // Indicated if an SDCH dictionary was advertised, and hence an SDCH - // compressed response is expected. We use this to help detect (accidental?) - // proxy corruption of a response, which sometimes marks SDCH content as - // having no content encoding <oops>. - bool sdch_dictionary_advertised_; + // A handle to the SDCH dictionaries that were advertised in this request. + // May be null. + scoped_ptr<SdchManager::DictionarySet> dictionaries_advertised_; // For SDCH latency experiments, when we are able to do SDCH, we may enable - // either an SDCH latency test xor a pass through test. The following bools + // either an SDCH latency test xor a pass through test. The following bools // indicate what we decided on for this instance. bool sdch_test_activated_; // Advertising a dictionary for sdch. bool sdch_test_control_; // Not even accepting-content sdch. @@ -219,7 +218,7 @@ // // TODO(jar): improve the quality of the gathered info by gathering most times // at a lower point in the network stack, assuring we have actual packet - // boundaries, rather than approximations. Also note that input byte count + // boundaries, rather than approximations. Also note that input byte count // as gathered here is post-SSL, and post-cache-fetch, and does not reflect // true packet arrival times in such cases.
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc index 5d32c6f..3cd8cf4 100644 --- a/net/url_request/url_request_job.cc +++ b/net/url_request/url_request_job.cc
@@ -20,7 +20,6 @@ #include "net/base/network_delegate.h" #include "net/filter/filter.h" #include "net/http/http_response_headers.h" -#include "net/url_request/url_request.h" namespace { @@ -255,6 +254,42 @@ void URLRequestJob::NotifyURLRequestDestroyed() { } +// static +GURL URLRequestJob::ComputeReferrerForRedirect( + URLRequest::ReferrerPolicy policy, + const std::string& referrer, + const GURL& redirect_destination) { + GURL original_referrer(referrer); + bool secure_referrer_but_insecure_destination = + original_referrer.SchemeIsSecure() && + !redirect_destination.SchemeIsSecure(); + bool same_origin = + original_referrer.GetOrigin() == redirect_destination.GetOrigin(); + switch (policy) { + case URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE: + return secure_referrer_but_insecure_destination ? GURL() + : original_referrer; + + case URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN: + if (same_origin) { + return original_referrer; + } else if (secure_referrer_but_insecure_destination) { + return GURL(); + } else { + return original_referrer.GetOrigin(); + } + + case URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN: + return same_origin ? original_referrer : original_referrer.GetOrigin(); + + case URLRequest::NEVER_CLEAR_REFERRER: + return original_referrer; + } + + NOTREACHED(); + return GURL(); +} + URLRequestJob::~URLRequestJob() { base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); if (power_monitor) @@ -863,15 +898,11 @@ request_->first_party_for_cookies(); } - // Suppress the referrer if we're redirecting out of https. - if (request_->referrer_policy() == - URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE && - GURL(request_->referrer()).SchemeIsSecure() && - !redirect_info.new_url.SchemeIsSecure()) { - redirect_info.new_referrer.clear(); - } else { - redirect_info.new_referrer = request_->referrer(); - } + // Alter the referrer if redirecting cross-origin (especially HTTP->HTTPS). + redirect_info.new_referrer = + ComputeReferrerForRedirect(request_->referrer_policy(), + request_->referrer(), + redirect_info.new_url).spec(); return redirect_info; }
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h index e824689..ceb71f5 100644 --- a/net/url_request/url_request_job.h +++ b/net/url_request/url_request_job.h
@@ -20,6 +20,7 @@ #include "net/base/upload_progress.h" #include "net/cookies/canonical_cookie.h" #include "net/url_request/redirect_info.h" +#include "net/url_request/url_request.h" #include "url/gurl.h" namespace net { @@ -36,7 +37,6 @@ class NetworkDelegate; class SSLCertRequestInfo; class SSLInfo; -class URLRequest; class UploadDataStream; class URLRequestStatus; class X509Certificate; @@ -227,6 +227,12 @@ // canceled by an explicit NetworkDelegate::NotifyURLRequestDestroyed() call. virtual void NotifyURLRequestDestroyed(); + // Given |policy|, |referrer|, and |redirect_destination|, returns the + // referrer URL mandated by |request|'s referrer policy. + static GURL ComputeReferrerForRedirect(URLRequest::ReferrerPolicy policy, + const std::string& referrer, + const GURL& redirect_destination); + protected: friend class base::RefCounted<URLRequestJob>; ~URLRequestJob() override;
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h index ca67e56..6329eab 100644 --- a/net/url_request/url_request_job_manager.h +++ b/net/url_request/url_request_job_manager.h
@@ -10,6 +10,7 @@ #include "base/synchronization/lock.h" #include "base/threading/platform_thread.h" +#include "net/base/net_export.h" #include "net/url_request/url_request.h" template <typename T> struct DefaultSingletonTraits; @@ -24,7 +25,7 @@ // URLRequest is designed to have all consumers on a single thread, and // so no attempt is made to support Interceptor instances being // registered/unregistered or in any way poked on multiple threads. -class URLRequestJobManager { +class NET_EXPORT URLRequestJobManager { public: // Returns the singleton instance. static URLRequestJobManager* GetInstance();
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc index 55a0f88..060a90e 100644 --- a/net/url_request/url_request_simple_job.cc +++ b/net/url_request/url_request_simple_job.cc
@@ -47,6 +47,11 @@ bool URLRequestSimpleJob::ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422489 URLRequestSimpleJob::ReadRawData")); + DCHECK(bytes_read); int remaining = byte_range_.last_byte_position() - data_offset_ + 1; if (buf_size > remaining)
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index 8f70ee7..6be7da3 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc
@@ -604,12 +604,6 @@ return can_throttle_requests_; } -int TestNetworkDelegate::OnBeforeSocketStreamConnect( - SocketStream* socket, - const CompletionCallback& callback) { - return OK; -} - bool TestNetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url,
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h index 1289db7..1c385b2 100644 --- a/net/url_request/url_request_test_util.h +++ b/net/url_request/url_request_test_util.h
@@ -325,8 +325,6 @@ bool OnCanAccessFile(const URLRequest& request, const base::FilePath& path) const override; bool OnCanThrottleRequest(const URLRequest& request) const override; - int OnBeforeSocketStreamConnect(SocketStream* stream, - const CompletionCallback& callback) override; bool OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url,
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 1d777dc..9892a69 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -3913,32 +3913,6 @@ } } -TEST_F(URLRequestTestHTTP, HTTPSToHTTPRedirectNoRefererTest) { - ASSERT_TRUE(test_server_.Start()); - - SpawnedTestServer https_test_server( - SpawnedTestServer::TYPE_HTTPS, SpawnedTestServer::kLocalhost, - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); - ASSERT_TRUE(https_test_server.Start()); - - // An https server is sent a request with an https referer, - // and responds with a redirect to an http url. The http - // server should not be sent the referer. - GURL http_destination = test_server_.GetURL(std::string()); - TestDelegate d; - scoped_ptr<URLRequest> req(default_context_.CreateRequest( - https_test_server.GetURL("server-redirect?" + http_destination.spec()), - DEFAULT_PRIORITY, &d, NULL)); - req->SetReferrer("https://www.referrer.com/"); - req->Start(); - base::RunLoop().Run(); - - EXPECT_EQ(1, d.response_started_count()); - EXPECT_EQ(1, d.received_redirect_count()); - EXPECT_EQ(http_destination, req->url()); - EXPECT_EQ(std::string(), req->referrer()); -} - TEST_F(URLRequestTestHTTP, RedirectLoadTiming) { ASSERT_TRUE(test_server_.Start()); @@ -6727,6 +6701,219 @@ EXPECT_EQ(2, default_network_delegate()->headers_received_count()); } +class URLRequestTestReferrerPolicy : public URLRequestTest { + public: + URLRequestTestReferrerPolicy() {} + + void InstantiateSameOriginServers(SpawnedTestServer::Type origin_type) { + origin_server_.reset(new SpawnedTestServer( + origin_type, SpawnedTestServer::kLocalhost, + origin_type == SpawnedTestServer::TYPE_HTTPS + ? base::FilePath(FILE_PATH_LITERAL("net/data/ssl")) + : base::FilePath( + FILE_PATH_LITERAL("net/data/url_request_unittest")))); + ASSERT_TRUE(origin_server_->Start()); + } + + void InstantiateCrossOriginServers(SpawnedTestServer::Type origin_type, + SpawnedTestServer::Type destination_type) { + origin_server_.reset(new SpawnedTestServer( + origin_type, SpawnedTestServer::kLocalhost, + origin_type == SpawnedTestServer::TYPE_HTTPS + ? base::FilePath(FILE_PATH_LITERAL("net/data/ssl")) + : base::FilePath( + FILE_PATH_LITERAL("net/data/url_request_unittest")))); + ASSERT_TRUE(origin_server_->Start()); + + destination_server_.reset(new SpawnedTestServer( + destination_type, SpawnedTestServer::kLocalhost, + destination_type == SpawnedTestServer::TYPE_HTTPS + ? base::FilePath(FILE_PATH_LITERAL("net/data/ssl")) + : base::FilePath( + FILE_PATH_LITERAL("net/data/url_request_unittest")))); + ASSERT_TRUE(destination_server_->Start()); + } + + void VerifyReferrerAfterRedirect(URLRequest::ReferrerPolicy policy, + const GURL& referrer, + const GURL& expected) { + // Create and execute the request: we'll only have a |destination_server_| + // if the origins are meant to be distinct. Otherwise, we'll use the + // |origin_server_| for both endpoints. + GURL destination_url = + destination_server_ ? destination_server_->GetURL("echoheader?Referer") + : origin_server_->GetURL("echoheader?Referer"); + GURL origin_url = + origin_server_->GetURL("server-redirect?" + destination_url.spec()); + + TestDelegate d; + scoped_ptr<URLRequest> req( + default_context_.CreateRequest(origin_url, DEFAULT_PRIORITY, &d, NULL)); + req->set_referrer_policy(policy); + req->SetReferrer(referrer.spec()); + req->Start(); + base::RunLoop().Run(); + + EXPECT_EQ(1, d.response_started_count()); + EXPECT_EQ(1, d.received_redirect_count()); + EXPECT_EQ(destination_url, req->url()); + EXPECT_TRUE(req->status().is_success()); + EXPECT_EQ(200, req->response_headers()->response_code()); + + EXPECT_EQ(expected.spec(), req->referrer()); + if (expected.is_empty()) + EXPECT_EQ("None", d.data_received()); + else + EXPECT_EQ(expected.spec(), d.data_received()); + } + + SpawnedTestServer* origin_server() const { return origin_server_.get(); } + + private: + scoped_ptr<SpawnedTestServer> origin_server_; + scoped_ptr<SpawnedTestServer> destination_server_; +}; + +TEST_F(URLRequestTestReferrerPolicy, HTTPToSameOriginHTTP) { + InstantiateSameOriginServers(SpawnedTestServer::TYPE_HTTP); + + VerifyReferrerAfterRedirect( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect( + URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect( + URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); +} + +TEST_F(URLRequestTestReferrerPolicy, HTTPToCrossOriginHTTP) { + InstantiateCrossOriginServers(SpawnedTestServer::TYPE_HTTP, + SpawnedTestServer::TYPE_HTTP); + + VerifyReferrerAfterRedirect( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect( + URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL(std::string())); + + VerifyReferrerAfterRedirect( + URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL(std::string())); + + VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); +} + +TEST_F(URLRequestTestReferrerPolicy, HTTPSToSameOriginHTTPS) { + InstantiateSameOriginServers(SpawnedTestServer::TYPE_HTTPS); + + VerifyReferrerAfterRedirect( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect( + URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect( + URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); +} + +TEST_F(URLRequestTestReferrerPolicy, HTTPSToCrossOriginHTTPS) { + InstantiateCrossOriginServers(SpawnedTestServer::TYPE_HTTPS, + SpawnedTestServer::TYPE_HTTPS); + + VerifyReferrerAfterRedirect( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect( + URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL(std::string())); + + VerifyReferrerAfterRedirect( + URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL(std::string())); + + VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); +} + +TEST_F(URLRequestTestReferrerPolicy, HTTPToHTTPS) { + InstantiateCrossOriginServers(SpawnedTestServer::TYPE_HTTP, + SpawnedTestServer::TYPE_HTTPS); + + VerifyReferrerAfterRedirect( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); + + VerifyReferrerAfterRedirect( + URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL(std::string())); + + VerifyReferrerAfterRedirect( + URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL(std::string())); + + VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); +} + +TEST_F(URLRequestTestReferrerPolicy, HTTPSToHTTP) { + InstantiateCrossOriginServers(SpawnedTestServer::TYPE_HTTPS, + SpawnedTestServer::TYPE_HTTP); + + VerifyReferrerAfterRedirect( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + origin_server()->GetURL("path/to/file.html"), GURL()); + + VerifyReferrerAfterRedirect( + URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), GURL()); + + VerifyReferrerAfterRedirect( + URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL(std::string())); + + VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER, + origin_server()->GetURL("path/to/file.html"), + origin_server()->GetURL("path/to/file.html")); +} + class HTTPSRequestTest : public testing::Test { public: HTTPSRequestTest() : default_context_(true) { @@ -7981,7 +8168,13 @@ EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED); } -TEST_F(HTTPSOCSPTest, RevokedStapled) { +// Disabled on NSS ports. See https://crbug.com/431716. +#if defined(USE_NSS) +#define MAYBE_RevokedStapled DISABLED_RevokedStapled +#else +#define MAYBE_RevokedStapled RevokedStapled +#endif +TEST_F(HTTPSOCSPTest, MAYBE_RevokedStapled) { if (!SystemSupportsOCSPStapling()) { LOG(WARNING) << "Skipping test because system doesn't support OCSP stapling";
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc index 769b802..08ee6ae 100644 --- a/net/websockets/websocket_basic_handshake_stream.cc +++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -39,8 +39,8 @@ #include "net/websockets/websocket_deflate_stream.h" #include "net/websockets/websocket_deflater.h" #include "net/websockets/websocket_extension_parser.h" +#include "net/websockets/websocket_handshake_challenge.h" #include "net/websockets/websocket_handshake_constants.h" -#include "net/websockets/websocket_handshake_handler.h" #include "net/websockets/websocket_handshake_request_info.h" #include "net/websockets/websocket_handshake_response_info.h" #include "net/websockets/websocket_stream.h" @@ -435,8 +435,8 @@ requested_sub_protocols_, &enriched_headers); - ComputeSecWebSocketAccept(handshake_challenge, - &handshake_challenge_response_); + handshake_challenge_response_ = + ComputeSecWebSocketAccept(handshake_challenge); DCHECK(connect_delegate_); scoped_ptr<WebSocketHandshakeRequestInfo> request(
diff --git a/net/websockets/websocket_handshake_challenge.cc b/net/websockets/websocket_handshake_challenge.cc new file mode 100644 index 0000000..3a1c3e8 --- /dev/null +++ b/net/websockets/websocket_handshake_challenge.cc
@@ -0,0 +1,20 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/websockets/websocket_handshake_challenge.h" + +#include "base/base64.h" +#include "base/sha1.h" +#include "net/websockets/websocket_handshake_constants.h" + +namespace net { + +std::string ComputeSecWebSocketAccept(const std::string& key) { + std::string accept; + std::string hash = base::SHA1HashString(key + websockets::kWebSocketGuid); + base::Base64Encode(hash, &accept); + return accept; +} + +} // namespace net
diff --git a/net/websockets/websocket_handshake_challenge.h b/net/websockets/websocket_handshake_challenge.h new file mode 100644 index 0000000..e21f2b0 --- /dev/null +++ b/net/websockets/websocket_handshake_challenge.h
@@ -0,0 +1,21 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_CHALLENGE_H_ +#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_CHALLENGE_H_ + +#include <string> + +#include "net/base/net_export.h" + +namespace net { + +// Given a WebSocket handshake challenge, compute the value that the server +// should return in the Sec-WebSocket-Accept header. +NET_EXPORT_PRIVATE std::string ComputeSecWebSocketAccept( + const std::string& key); + +} // namespace net + +#endif // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_CHALLENGE_H_
diff --git a/net/websockets/websocket_handshake_challenge_test.cc b/net/websockets/websocket_handshake_challenge_test.cc new file mode 100644 index 0000000..d7e45ca --- /dev/null +++ b/net/websockets/websocket_handshake_challenge_test.cc
@@ -0,0 +1,24 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/websockets/websocket_handshake_challenge.h" + +#include <string> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +// Test the example challenge from the RFC6455. +TEST(WebSocketHandshakeChallengeTest, RFC6455) { + const std::string key = "dGhlIHNhbXBsZSBub25jZQ=="; + std::string accept = ComputeSecWebSocketAccept(key); + EXPECT_EQ("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", accept); +} + +} // namespace + +} // namespace net
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc deleted file mode 100644 index 6bcc230..0000000 --- a/net/websockets/websocket_handshake_handler.cc +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/websockets/websocket_handshake_handler.h" - -#include "base/base64.h" -#include "base/logging.h" -#include "base/sha1.h" -#include "net/websockets/websocket_handshake_constants.h" - -namespace net { - -void ComputeSecWebSocketAccept(const std::string& key, - std::string* accept) { - DCHECK(accept); - - std::string hash = - base::SHA1HashString(key + websockets::kWebSocketGuid); - base::Base64Encode(hash, accept); -} - -} // namespace net
diff --git a/net/websockets/websocket_handshake_handler.h b/net/websockets/websocket_handshake_handler.h deleted file mode 100644 index c65e6d9..0000000 --- a/net/websockets/websocket_handshake_handler.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_ -#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_ - -#include <string> - -namespace net { - -// Given a WebSocket handshake challenge, compute the correct response. -// TODO(ricea): There should probably be a test for this. -void ComputeSecWebSocketAccept(const std::string& key, - std::string* accept); - -} // namespace net - -#endif // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
diff --git a/net/websockets/websocket_handshake_handler_test.cc b/net/websockets/websocket_handshake_handler_test.cc deleted file mode 100644 index 8eff571..0000000 --- a/net/websockets/websocket_handshake_handler_test.cc +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/websockets/websocket_handshake_handler.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { - -namespace { - -// TODO(ricea): Put a test for ComputeSecWebSocketAccept() here. - -} // namespace - -} // namespace net
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn index 23baf4e..0f8f86a 100644 --- a/sandbox/linux/BUILD.gn +++ b/sandbox/linux/BUILD.gn
@@ -68,6 +68,7 @@ test("sandbox_linux_unittests") { sources = [ "services/scoped_process_unittest.cc", + "services/syscall_wrappers_unittest.cc", "services/thread_helpers_unittests.cc", "services/yama_unittests.cc", "syscall_broker/broker_process_unittest.cc", @@ -75,6 +76,7 @@ "tests/scoped_temporary_file.cc", "tests/scoped_temporary_file.h", "tests/scoped_temporary_file_unittest.cc", + "tests/test_utils_unittest.cc", "tests/unit_tests_unittest.cc", ] @@ -150,15 +152,12 @@ "bpf_dsl/policy_compiler.cc", "bpf_dsl/policy_compiler.h", "bpf_dsl/trap_registry.h", - "seccomp-bpf/basicblock.cc", - "seccomp-bpf/basicblock.h", "seccomp-bpf/codegen.cc", "seccomp-bpf/codegen.h", "seccomp-bpf/die.cc", "seccomp-bpf/die.h", "seccomp-bpf/errorcode.cc", "seccomp-bpf/errorcode.h", - "seccomp-bpf/instruction.h", "seccomp-bpf/linux_seccomp.h", "seccomp-bpf/sandbox_bpf.cc", "seccomp-bpf/sandbox_bpf.h", @@ -225,6 +224,8 @@ "services/init_process_reaper.h", "services/scoped_process.cc", "services/scoped_process.h", + "services/syscall_wrappers.cc", + "services/syscall_wrappers.h", "services/thread_helpers.cc", "services/thread_helpers.h", "services/yama.h",
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc b/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc index b3d9126..66669e7 100644 --- a/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc +++ b/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc
@@ -41,6 +41,7 @@ #include "sandbox/linux/seccomp-bpf/syscall.h" #include "sandbox/linux/seccomp-bpf/trap.h" #include "sandbox/linux/services/linux_syscalls.h" +#include "sandbox/linux/services/syscall_wrappers.h" #include "sandbox/linux/syscall_broker/broker_process.h" #include "sandbox/linux/tests/scoped_temporary_file.h" #include "sandbox/linux/tests/unit_tests.h" @@ -203,7 +204,7 @@ BPF_TEST_C(SandboxBPF, ApplyBasicWhitelistPolicy, WhitelistGetpidPolicy) { // getpid() should be allowed errno = 0; - BPF_ASSERT(syscall(__NR_getpid) > 0); + BPF_ASSERT(sys_getpid() > 0); BPF_ASSERT(errno == 0); // getpgid() should be denied @@ -246,7 +247,7 @@ int /* (*BPF_AUX) */) { // getpid() should work properly errno = 0; - BPF_ASSERT(syscall(__NR_getpid) > 0); + BPF_ASSERT(sys_getpid() > 0); BPF_ASSERT(errno == 0); // Our Auxiliary Data, should be reset by the signal handler @@ -512,7 +513,7 @@ // Verify that within the callback function all filtering is temporarily // disabled. - BPF_ASSERT(syscall(__NR_getpid) > 1); + BPF_ASSERT(sys_getpid() > 1); // Verify that we can now call the underlying system call without causing // infinite recursion. @@ -549,7 +550,7 @@ }; BPF_TEST(SandboxBPF, GreyListedPolicy, GreyListedPolicy, int /* (*BPF_AUX) */) { - BPF_ASSERT(syscall(__NR_getpid) == -1); + BPF_ASSERT(sys_getpid() == -1); BPF_ASSERT(errno == EPERM); BPF_ASSERT(*BPF_AUX == 0); BPF_ASSERT(syscall(__NR_geteuid) == syscall(__NR_getuid)); @@ -2098,7 +2099,7 @@ BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); // getpid is allowed. - BPF_ASSERT_EQ(my_pid, syscall(__NR_getpid)); + BPF_ASSERT_EQ(my_pid, sys_getpid()); // write to stdout is skipped and returns a fake value. BPF_ASSERT_EQ(kExpectedReturnValue,
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi index aa6341d..08a5c43 100644 --- a/sandbox/linux/sandbox_linux.gypi +++ b/sandbox/linux/sandbox_linux.gypi
@@ -130,15 +130,12 @@ 'bpf_dsl/policy_compiler.cc', 'bpf_dsl/policy_compiler.h', 'bpf_dsl/trap_registry.h', - 'seccomp-bpf/basicblock.cc', - 'seccomp-bpf/basicblock.h', 'seccomp-bpf/codegen.cc', 'seccomp-bpf/codegen.h', 'seccomp-bpf/die.cc', 'seccomp-bpf/die.h', 'seccomp-bpf/errorcode.cc', 'seccomp-bpf/errorcode.h', - 'seccomp-bpf/instruction.h', 'seccomp-bpf/linux_seccomp.h', 'seccomp-bpf/sandbox_bpf.cc', 'seccomp-bpf/sandbox_bpf.h', @@ -153,6 +150,7 @@ ], 'dependencies': [ '../base/base.gyp:base', + 'sandbox_services', 'sandbox_services_headers', ], 'defines': [ @@ -182,6 +180,7 @@ ], 'dependencies': [ '../base/base.gyp:base', + 'sandbox_services', 'seccomp_bpf', ], 'defines': [ @@ -224,6 +223,8 @@ 'services/init_process_reaper.h', 'services/scoped_process.cc', 'services/scoped_process.h', + 'services/syscall_wrappers.cc', + 'services/syscall_wrappers.h', 'services/thread_helpers.cc', 'services/thread_helpers.h', 'services/yama.cc',
diff --git a/sandbox/linux/sandbox_linux_test_sources.gypi b/sandbox/linux/sandbox_linux_test_sources.gypi index f246ebb..cefe962 100644 --- a/sandbox/linux/sandbox_linux_test_sources.gypi +++ b/sandbox/linux/sandbox_linux_test_sources.gypi
@@ -8,6 +8,7 @@ 'dependencies': [ 'sandbox', 'sandbox_linux_test_utils', + 'sandbox_services', '../base/base.gyp:base', '../base/base.gyp:test_support_base', '../testing/gtest.gyp:gtest', @@ -17,6 +18,7 @@ ], 'sources': [ 'services/scoped_process_unittest.cc', + 'services/syscall_wrappers_unittest.cc', 'services/thread_helpers_unittests.cc', 'services/yama_unittests.cc', 'syscall_broker/broker_process_unittest.cc', @@ -24,6 +26,7 @@ 'tests/scoped_temporary_file.cc', 'tests/scoped_temporary_file.h', 'tests/scoped_temporary_file_unittest.cc', + 'tests/test_utils_unittest.cc', 'tests/unit_tests_unittest.cc', ], 'conditions': [
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc index 8f11bbb..69d32bc 100644 --- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc +++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -19,6 +19,7 @@ #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/services/linux_syscalls.h" +#include "sandbox/linux/services/syscall_wrappers.h" // Changing this implementation will have an effect on *all* policies. // Currently this means: Renderer/Worker, GPU, Flash and NaCl. @@ -237,12 +238,13 @@ BaselinePolicy::BaselinePolicy() : BaselinePolicy(EPERM) {} BaselinePolicy::BaselinePolicy(int fs_denied_errno) - : fs_denied_errno_(fs_denied_errno), policy_pid_(syscall(__NR_getpid)) {} + : fs_denied_errno_(fs_denied_errno), policy_pid_(sys_getpid()) { +} BaselinePolicy::~BaselinePolicy() { // Make sure that this policy is created, used and destroyed by a single // process. - DCHECK_EQ(syscall(__NR_getpid), policy_pid_); + DCHECK_EQ(sys_getpid(), policy_pid_); } ResultExpr BaselinePolicy::EvaluateSyscall(int sysno) const { @@ -250,7 +252,7 @@ DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); // Make sure that this policy is used in the creating process. if (1 == sysno) { - DCHECK_EQ(syscall(__NR_getpid), policy_pid_); + DCHECK_EQ(sys_getpid(), policy_pid_); } return EvaluateSyscallImpl(fs_denied_errno_, policy_pid_, sysno); }
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc index a71975b..4955dfb 100644 --- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc +++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -32,34 +32,15 @@ #include "sandbox/linux/seccomp-bpf/syscall.h" #include "sandbox/linux/services/android_futex.h" #include "sandbox/linux/services/linux_syscalls.h" +#include "sandbox/linux/services/syscall_wrappers.h" #include "sandbox/linux/services/thread_helpers.h" +#include "sandbox/linux/tests/test_utils.h" #include "sandbox/linux/tests/unit_tests.h" namespace sandbox { namespace { -// |pid| is the return value of a fork()-like call. This -// makes sure that if fork() succeeded the child exits -// and the parent waits for it. -void HandlePostForkReturn(pid_t pid) { - const int kChildExitCode = 1; - if (pid > 0) { - int status = 0; - PCHECK(pid == HANDLE_EINTR(waitpid(pid, &status, 0))); - CHECK(WIFEXITED(status)); - CHECK_EQ(kChildExitCode, WEXITSTATUS(status)); - } else if (pid == 0) { - _exit(kChildExitCode); - } -} - -// Check that HandlePostForkReturn works. -TEST(BaselinePolicy, HandlePostForkReturn) { - pid_t pid = fork(); - HandlePostForkReturn(pid); -} - // This also tests that read(), write() and fstat() are allowed. void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) { BPF_ASSERT_LE(0, read_end.get()); @@ -106,36 +87,39 @@ errno = 0; pid_t pid = fork(); const int fork_errno = errno; - HandlePostForkReturn(pid); + TestUtils::HandlePostForkReturn(pid); BPF_ASSERT_EQ(-1, pid); BPF_ASSERT_EQ(EPERM, fork_errno); } pid_t ForkX86Glibc() { - return syscall(__NR_clone, CLONE_PARENT_SETTID | SIGCHLD); + static pid_t ptid; + return sys_clone(CLONE_PARENT_SETTID | SIGCHLD, nullptr, &ptid, nullptr, + nullptr); } BPF_TEST_C(BaselinePolicy, ForkX86Eperm, BaselinePolicy) { errno = 0; pid_t pid = ForkX86Glibc(); const int fork_errno = errno; - HandlePostForkReturn(pid); + TestUtils::HandlePostForkReturn(pid); BPF_ASSERT_EQ(-1, pid); BPF_ASSERT_EQ(EPERM, fork_errno); } pid_t ForkARMGlibc() { - return syscall(__NR_clone, - CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD); + static pid_t ctid; + return sys_clone(CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, nullptr, + nullptr, &ctid, nullptr); } BPF_TEST_C(BaselinePolicy, ForkArmEperm, BaselinePolicy) { errno = 0; pid_t pid = ForkARMGlibc(); const int fork_errno = errno; - HandlePostForkReturn(pid); + TestUtils::HandlePostForkReturn(pid); BPF_ASSERT_EQ(-1, pid); BPF_ASSERT_EQ(EPERM, fork_errno); @@ -150,8 +134,8 @@ DisallowedCloneFlagCrashes, DEATH_SEGV_MESSAGE(GetCloneErrorMessageContentForTests()), BaselinePolicy) { - pid_t pid = syscall(__NR_clone, CLONE_THREAD | SIGCHLD); - HandlePostForkReturn(pid); + pid_t pid = sys_clone(CLONE_THREAD | SIGCHLD); + TestUtils::HandlePostForkReturn(pid); } BPF_DEATH_TEST_C(BaselinePolicy,
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc index 162b371..42be00b 100644 --- a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc +++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -17,6 +17,7 @@ #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/seccomp-bpf/syscall.h" #include "sandbox/linux/services/linux_syscalls.h" +#include "sandbox/linux/services/syscall_wrappers.h" #if defined(__mips__) // __NR_Linux, is defined in <asm/unistd.h>. @@ -223,7 +224,7 @@ case __NR_sched_setattr: case __NR_sched_setparam: case __NR_sched_setscheduler: - const pid_t tid = syscall(__NR_gettid); + const pid_t tid = sys_gettid(); // The first argument is the pid. If is our thread id, then replace it // with 0, which is equivalent and allowed by the policy. if (args.args[0] == static_cast<uint64_t>(tid)) {
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc index 82cdc8d..2d3e7de 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -286,5 +286,9 @@ } } +ResultExpr RestrictPrlimit64(pid_t target_pid) { + const Arg<pid_t> pid(0); + return If(pid == 0 || pid == target_pid, Allow()).Else(CrashSIGSYS()); +} } // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h index ec30511..8bde616 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -87,6 +87,10 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno); +// Restricts the |pid| argument of prlimit64 to 0 (meaning the calling process) +// or target_pid. +SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrlimit64(pid_t target_pid); + } // namespace sandbox. #endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc index 83e8489..264ee4d 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
@@ -6,7 +6,9 @@ #include <errno.h> #include <sched.h> +#include <sys/resource.h> #include <sys/syscall.h> +#include <sys/types.h> #include <time.h> #include <unistd.h> @@ -23,6 +25,7 @@ #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/seccomp-bpf/syscall.h" #include "sandbox/linux/services/linux_syscalls.h" +#include "sandbox/linux/services/syscall_wrappers.h" #include "sandbox/linux/tests/unit_tests.h" #if !defined(OS_ANDROID) @@ -163,7 +166,7 @@ void SchedGetParamThread(base::WaitableEvent* thread_run) { const pid_t pid = getpid(); - const pid_t tid = syscall(__NR_gettid); + const pid_t tid = sys_gettid(); BPF_ASSERT_NE(pid, tid); struct sched_param current_pid_param; @@ -208,6 +211,35 @@ sched_getparam(kInitPID, ¶m); } +class RestrictPrlimit64Policy : public bpf_dsl::Policy { + public: + RestrictPrlimit64Policy() {} + ~RestrictPrlimit64Policy() override {} + + ResultExpr EvaluateSyscall(int sysno) const override { + switch (sysno) { + case __NR_prlimit64: + return RestrictPrlimit64(getpid()); + default: + return Allow(); + } + } +}; + +BPF_TEST_C(ParameterRestrictions, prlimit64_allowed, RestrictPrlimit64Policy) { + BPF_ASSERT_EQ(0, syscall(__NR_prlimit64, 0, RLIMIT_AS, NULL, NULL)); + BPF_ASSERT_EQ(0, syscall(__NR_prlimit64, getpid(), RLIMIT_AS, NULL, NULL)); +} + +BPF_DEATH_TEST_C(ParameterRestrictions, + prlimit64_crash_not_self, + DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), + RestrictPrlimit64Policy) { + const pid_t kInitPID = 1; + BPF_ASSERT_NE(kInitPID, getpid()); + syscall(__NR_prlimit64, kInitPID, RLIMIT_AS, NULL, NULL); +} + } // namespace } // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/basicblock.cc b/sandbox/linux/seccomp-bpf/basicblock.cc deleted file mode 100644 index eb857f0..0000000 --- a/sandbox/linux/seccomp-bpf/basicblock.cc +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "sandbox/linux/seccomp-bpf/basicblock.h" - -namespace sandbox { - -BasicBlock::BasicBlock() {} - -BasicBlock::~BasicBlock() {} - -} // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/basicblock.h b/sandbox/linux/seccomp-bpf/basicblock.h deleted file mode 100644 index d15a372..0000000 --- a/sandbox/linux/seccomp-bpf/basicblock.h +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SANDBOX_LINUX_SECCOMP_BPF_BASICBLOCK_H__ -#define SANDBOX_LINUX_SECCOMP_BPF_BASICBLOCK_H__ - -#include <vector> - -#include "sandbox/linux/seccomp-bpf/instruction.h" - -namespace sandbox { - -struct BasicBlock { - BasicBlock(); - ~BasicBlock(); - - // Our implementation of the code generator uses a "Less" operator to - // identify common sequences of basic blocks. This would normally be - // really easy to do, but STL requires us to wrap the comparator into - // a class. We begrudgingly add some code here that provides this wrapping. - template <class T> - class Less { - public: - Less(const T& data, - int (*cmp)(const BasicBlock*, const BasicBlock*, const T& data)) - : data_(data), cmp_(cmp) {} - - bool operator()(const BasicBlock* a, const BasicBlock* b) const { - return cmp_(a, b, data_) < 0; - } - - private: - const T& data_; - int (*cmp_)(const BasicBlock*, const BasicBlock*, const T&); - }; - - // Basic blocks are essentially nothing more than a set of instructions. - std::vector<Instruction*> instructions; - - // In order to compute relative branch offsets we need to keep track of - // how far our block is away from the very last basic block. The "offset_" - // is measured in number of BPF instructions. - int offset; -}; - -} // namespace sandbox - -#endif // SANDBOX_LINUX_SECCOMP_BPF_BASICBLOCK_H__
diff --git a/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc b/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc index 9d2bb79..192e68d 100644 --- a/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc +++ b/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
@@ -17,6 +17,7 @@ #include "sandbox/linux/bpf_dsl/policy.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/services/linux_syscalls.h" +#include "sandbox/linux/services/syscall_wrappers.h" #include "sandbox/linux/tests/unit_tests.h" #include "testing/gtest/include/gtest/gtest.h" @@ -82,13 +83,11 @@ class EnosysPtracePolicy : public bpf_dsl::Policy { public: - EnosysPtracePolicy() { - my_pid_ = syscall(__NR_getpid); - } + EnosysPtracePolicy() { my_pid_ = sys_getpid(); } virtual ~EnosysPtracePolicy() { // Policies should be able to bind with the process on which they are // created. They should never be created in a parent process. - BPF_ASSERT_EQ(my_pid_, syscall(__NR_getpid)); + BPF_ASSERT_EQ(my_pid_, sys_getpid()); } virtual ResultExpr EvaluateSyscall(int system_call_number) const override { @@ -96,7 +95,7 @@ if (system_call_number == __NR_ptrace) { // The EvaluateSyscall function should run in the process that created // the current object. - BPF_ASSERT_EQ(my_pid_, syscall(__NR_getpid)); + BPF_ASSERT_EQ(my_pid_, sys_getpid()); return Error(ENOSYS); } else { return Allow();
diff --git a/sandbox/linux/seccomp-bpf/codegen.cc b/sandbox/linux/seccomp-bpf/codegen.cc index 18d26da..3ed06cb 100644 --- a/sandbox/linux/seccomp-bpf/codegen.cc +++ b/sandbox/linux/seccomp-bpf/codegen.cc
@@ -6,590 +6,148 @@ #include <linux/filter.h> -#include <set> +#include <limits> +#include <utility> #include "base/logging.h" -#include "sandbox/linux/seccomp-bpf/basicblock.h" -#include "sandbox/linux/seccomp-bpf/die.h" -#include "sandbox/linux/seccomp-bpf/instruction.h" + +// This CodeGen implementation strives for simplicity while still +// generating acceptable BPF programs under typical usage patterns +// (e.g., by PolicyCompiler). +// +// The key to its simplicity is that BPF programs only support forward +// jumps/branches, which allows constraining the DAG construction API +// to make instruction nodes immutable. Immutable nodes admits a +// simple greedy approach of emitting new instructions as needed and +// then reusing existing ones that have already been emitted. This +// cleanly avoids any need to compute basic blocks or apply +// topological sorting because the API effectively sorts instructions +// for us (e.g., before MakeInstruction() can be called to emit a +// branch instruction, it must have already been called for each +// branch path). +// +// This greedy algorithm is not without (theoretical) weakness though: +// +// 1. In the general case, we don't eliminate dead code. If needed, +// we could trace back through the program in Compile() and elide +// any unneeded instructions, but in practice we only emit live +// instructions anyway. +// +// 2. By not dividing instructions into basic blocks and sorting, we +// lose an opportunity to move non-branch/non-return instructions +// adjacent to their successor instructions, which means we might +// need to emit additional jumps. But in practice, they'll +// already be nearby as long as callers don't go out of their way +// to interleave MakeInstruction() calls for unrelated code +// sequences. namespace sandbox { -// Unfortunately this needs to be defined out-of-line because inline -// initializing a static member to "nullptr" requires "constexpr", -// which is currently banned by the Chromium style guide. -const CodeGen::Node CodeGen::kNullNode = nullptr; +// kBranchRange is the maximum value that can be stored in +// sock_filter's 8-bit jt and jf fields. +const size_t kBranchRange = std::numeric_limits<uint8_t>::max(); -CodeGen::CodeGen() : compiled_(false) {} +const CodeGen::Node CodeGen::kNullNode; + +CodeGen::CodeGen() : program_(), memos_() { +} CodeGen::~CodeGen() { - for (Instructions::iterator iter = instructions_.begin(); - iter != instructions_.end(); - ++iter) { - delete *iter; - } - for (BasicBlocks::iterator iter = basic_blocks_.begin(); - iter != basic_blocks_.end(); - ++iter) { - delete *iter; - } +} + +void CodeGen::Compile(CodeGen::Node head, Program* out) { + DCHECK(out); + out->assign(program_.rbegin() + Offset(head), program_.rend()); } CodeGen::Node CodeGen::MakeInstruction(uint16_t code, uint32_t k, Node jt, Node jf) { - Node insn; + // To avoid generating redundant code sequences, we memoize the + // results from AppendInstruction(). + auto res = memos_.insert(std::make_pair(MemoKey(code, k, jt, jf), kNullNode)); + CodeGen::Node* node = &res.first->second; + if (res.second) { // Newly inserted memo entry. + *node = AppendInstruction(code, k, jt, jf); + } + return *node; +} + +CodeGen::Node CodeGen::AppendInstruction(uint16_t code, + uint32_t k, + Node jt, + Node jf) { if (BPF_CLASS(code) == BPF_JMP) { - CHECK_NE(kNullNode, jt); - if (BPF_OP(code) == BPF_JA) { - CHECK_EQ(kNullNode, jf); - } else { - CHECK_NE(kNullNode, jf); - } - insn = new Instruction(code, k, jt, jf); + CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed"; + + // We need to check |jt| twice because it might get pushed + // out-of-range by appending a jump for |jf|. + jt = WithinRange(jt, kBranchRange); + jf = WithinRange(jf, kBranchRange); + jt = WithinRange(jt, kBranchRange); + return Append(code, k, Offset(jt), Offset(jf)); + } + + CHECK_EQ(kNullNode, jf) << "Non-branch instructions shouldn't provide jf"; + if (BPF_CLASS(code) == BPF_RET) { + CHECK_EQ(kNullNode, jt) << "Return instructions shouldn't provide jt"; } else { - if (BPF_CLASS(code) == BPF_RET) { - CHECK_EQ(kNullNode, jt); - } else { - CHECK_NE(kNullNode, jt); - } - CHECK_EQ(kNullNode, jf); - insn = new Instruction(code, k, jt); + // For non-branch/non-return instructions, execution always + // proceeds to the next instruction; so we need to arrange for + // that to be |jt|. + jt = WithinRange(jt, 0); } - instructions_.push_back(insn); - return insn; + return Append(code, k, 0, 0); } -void CodeGen::FindBranchTargets(const Instruction& instructions, - BranchTargets* branch_targets) { - // Follow all possible paths through the "instructions" graph and compute - // a list of branch targets. This will later be needed to compute the - // boundaries of basic blocks. - // We maintain a set of all instructions that we have previously seen. This - // set ultimately converges on all instructions in the program. - std::set<const Instruction*> seen_instructions; - Instructions stack; - for (const Instruction* insn = &instructions; insn;) { - seen_instructions.insert(insn); - if (BPF_CLASS(insn->code) == BPF_JMP) { - // Found a jump. Increase count of incoming edges for each of the jump - // targets. - ++(*branch_targets)[insn->jt_ptr]; - if (BPF_OP(insn->code) != BPF_JA) { - ++(*branch_targets)[insn->jf_ptr]; - stack.push_back(const_cast<Instruction*>(insn)); - } - // Start a recursive decent for depth-first traversal. - if (seen_instructions.find(insn->jt_ptr) == seen_instructions.end()) { - // We haven't seen the "true" branch yet. Traverse it now. We have - // already remembered the "false" branch on the stack and will - // traverse it later. - insn = insn->jt_ptr; - continue; - } else { - // Now try traversing the "false" branch. - insn = NULL; - } - } else { - // This is a non-jump instruction, just continue to the next instruction - // (if any). It's OK if "insn" becomes NULL when reaching a return - // instruction. - if (!insn->next != (BPF_CLASS(insn->code) == BPF_RET)) { - SANDBOX_DIE( - "Internal compiler error; return instruction must be at " - "the end of the BPF program"); - } - if (seen_instructions.find(insn->next) == seen_instructions.end()) { - insn = insn->next; - } else { - // We have seen this instruction before. That could happen if it is - // a branch target. No need to continue processing. - insn = NULL; - } - } - while (!insn && !stack.empty()) { - // We are done processing all the way to a leaf node, backtrack up the - // stack to any branches that we haven't processed yet. By definition, - // this has to be a "false" branch, as we always process the "true" - // branches right away. - insn = stack.back(); - stack.pop_back(); - if (seen_instructions.find(insn->jf_ptr) == seen_instructions.end()) { - // We haven't seen the "false" branch yet. So, that's where we'll - // go now. - insn = insn->jf_ptr; - } else { - // We have seen both the "true" and the "false" branch, continue - // up the stack. - if (seen_instructions.find(insn->jt_ptr) == seen_instructions.end()) { - SANDBOX_DIE( - "Internal compiler error; cannot find all " - "branch targets"); - } - insn = NULL; - } - } +CodeGen::Node CodeGen::WithinRange(Node target, size_t range) { + if (Offset(target) > range) { + // TODO(mdempsky): If |range > 0|, we might be able to reuse an + // existing instruction within that range. + + // TODO(mdempsky): If |target| is a branch or return, it might be + // possible to duplicate that instruction rather than jump to it. + + // Fall back to emitting a jump instruction. + target = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0); } - return; + + CHECK_LE(Offset(target), range) << "ICE: Failed to bring target within range"; + return target; } -BasicBlock* CodeGen::MakeBasicBlock(Instruction* head, Instruction* tail) { - // Iterate over all the instructions between "head" and "tail" and - // insert them into a new basic block. - BasicBlock* bb = new BasicBlock; - for (;; head = head->next) { - bb->instructions.push_back(head); - if (head == tail) { - break; - } - if (BPF_CLASS(head->code) == BPF_JMP) { - SANDBOX_DIE("Found a jump inside of a basic block"); - } +CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) { + if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_JA) { + CHECK_LE(jt, kBranchRange); + CHECK_LE(jf, kBranchRange); + } else { + CHECK_EQ(0U, jt); + CHECK_EQ(0U, jf); } - basic_blocks_.push_back(bb); - return bb; + + CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS)); + program_.push_back(sock_filter{code, jt, jf, k}); + return program_.size() - 1; } -void CodeGen::AddBasicBlock(Instruction* head, - Instruction* tail, - const BranchTargets& branch_targets, - TargetsToBlocks* basic_blocks, - BasicBlock** firstBlock) { - // Add a new basic block to "basic_blocks". Also set "firstBlock", if it - // has not been set before. - BranchTargets::const_iterator iter = branch_targets.find(head); - if ((iter == branch_targets.end()) != !*firstBlock || - !*firstBlock != basic_blocks->empty()) { - SANDBOX_DIE( - "Only the very first basic block should have no " - "incoming jumps"); - } - BasicBlock* bb = MakeBasicBlock(head, tail); - if (!*firstBlock) { - *firstBlock = bb; - } - (*basic_blocks)[head] = bb; - return; +size_t CodeGen::Offset(Node target) const { + CHECK_LT(target, program_.size()) << "Bogus offset target node"; + return (program_.size() - 1) - target; } -BasicBlock* CodeGen::CutGraphIntoBasicBlocks( - Instruction* instructions, - const BranchTargets& branch_targets, - TargetsToBlocks* basic_blocks) { - // Textbook implementation of a basic block generator. All basic blocks - // start with a branch target and end with either a return statement or - // a jump (or are followed by an instruction that forms the beginning of a - // new block). Both conditional and "always" jumps are supported. - BasicBlock* first_block = NULL; - std::set<const Instruction*> seen_instructions; - Instructions stack; - Instruction* tail = NULL; - Instruction* head = instructions; - for (Instruction* insn = head; insn;) { - if (seen_instructions.find(insn) != seen_instructions.end()) { - // We somehow went in a circle. This should never be possible. Not even - // cyclic graphs are supposed to confuse us this much. - SANDBOX_DIE("Internal compiler error; cannot compute basic blocks"); - } - seen_instructions.insert(insn); - if (tail && branch_targets.find(insn) != branch_targets.end()) { - // We reached a branch target. Start a new basic block (this means, - // flushing the previous basic block first). - AddBasicBlock(head, tail, branch_targets, basic_blocks, &first_block); - head = insn; - } - if (BPF_CLASS(insn->code) == BPF_JMP) { - // We reached a jump instruction, this completes our current basic - // block. Flush it and continue by traversing both the true and the - // false branch of the jump. We need to maintain a stack to do so. - AddBasicBlock(head, insn, branch_targets, basic_blocks, &first_block); - if (BPF_OP(insn->code) != BPF_JA) { - stack.push_back(insn->jf_ptr); - } - insn = insn->jt_ptr; - - // If we are jumping to an instruction that we have previously - // processed, we are done with this branch. Continue by backtracking - // up the stack. - while (seen_instructions.find(insn) != seen_instructions.end()) { - backtracking: - if (stack.empty()) { - // We successfully traversed all reachable instructions. - return first_block; - } else { - // Going up the stack. - insn = stack.back(); - stack.pop_back(); - } - } - // Starting a new basic block. - tail = NULL; - head = insn; - } else { - // We found a non-jumping instruction, append it to current basic - // block. - tail = insn; - insn = insn->next; - if (!insn) { - // We reached a return statement, flush the current basic block and - // backtrack up the stack. - AddBasicBlock(head, tail, branch_targets, basic_blocks, &first_block); - goto backtracking; - } - } - } - return first_block; -} - -// We define a comparator that inspects the sequence of instructions in our -// basic block and any blocks referenced by this block. This function can be -// used in a "less" comparator for the purpose of storing pointers to basic -// blocks in STL containers; this gives an easy option to use STL to find -// shared tail sequences of basic blocks. -static int PointerCompare(const BasicBlock* block1, - const BasicBlock* block2, - const TargetsToBlocks& blocks) { - // Return <0, 0, or >0 depending on the ordering of "block1" and "block2". - // If we are looking at the exact same block, this is trivial and we don't - // need to do a full comparison. - if (block1 == block2) { - return 0; - } - - // We compare the sequence of instructions in both basic blocks. - const Instructions& insns1 = block1->instructions; - const Instructions& insns2 = block2->instructions; - // Basic blocks should never be empty. - CHECK(!insns1.empty()); - CHECK(!insns2.empty()); - - Instructions::const_iterator iter1 = insns1.begin(); - Instructions::const_iterator iter2 = insns2.begin(); - for (;; ++iter1, ++iter2) { - // If we have reached the end of the sequence of instructions in one or - // both basic blocks, we know the relative ordering between the two blocks - // and can return. - if (iter1 == insns1.end() || iter2 == insns2.end()) { - if (iter1 != insns1.end()) { - return 1; - } - if (iter2 != insns2.end()) { - return -1; - } - - // If the two blocks are the same length (and have elementwise-equal code - // and k fields) and their last instructions are neither a JMP nor a RET - // (which is the only way we can reach this point), then we must compare - // their successors. - Instruction* const insns1_last = insns1.back(); - Instruction* const insns2_last = insns2.back(); - CHECK(BPF_CLASS(insns1_last->code) != BPF_JMP && - BPF_CLASS(insns1_last->code) != BPF_RET); - - // Non jumping instructions will always have a valid next instruction. - CHECK(insns1_last->next); - CHECK(insns2_last->next); - return PointerCompare(blocks.find(insns1_last->next)->second, - blocks.find(insns2_last->next)->second, - blocks); - } - - // Compare the individual fields for both instructions. - const Instruction& insn1 = **iter1; - const Instruction& insn2 = **iter2; - if (insn1.code != insn2.code) { - return insn1.code - insn2.code; - } - if (insn1.k != insn2.k) { - return insn1.k - insn2.k; - } - - // Sanity check: If we're looking at a JMP or RET instruction, by definition - // it should be the last instruction of the basic block. - if (BPF_CLASS(insn1.code) == BPF_JMP || BPF_CLASS(insn1.code) == BPF_RET) { - CHECK_EQ(insns1.back(), &insn1); - CHECK_EQ(insns2.back(), &insn2); - } - - // RET instructions terminate execution, and only JMP instructions use the - // jt_ptr and jf_ptr fields. Anything else can continue to the next - // instruction in the basic block. - if (BPF_CLASS(insn1.code) == BPF_RET) { - return 0; - } else if (BPF_CLASS(insn1.code) != BPF_JMP) { - continue; - } - - // Recursively compare the "true" and "false" branches. - // A well-formed BPF program can't have any cycles, so we know - // that our recursive algorithm will ultimately terminate. - // In the unlikely event that the programmer made a mistake and - // went out of the way to give us a cyclic program, we will crash - // with a stack overflow. We are OK with that. - if (BPF_OP(insn1.code) != BPF_JA) { - int c = PointerCompare(blocks.find(insn1.jf_ptr)->second, - blocks.find(insn2.jf_ptr)->second, - blocks); - if (c != 0) { - return c; - } - } - return PointerCompare(blocks.find(insn1.jt_ptr)->second, - blocks.find(insn2.jt_ptr)->second, - blocks); - } -} - -void CodeGen::MergeTails(TargetsToBlocks* blocks) { - // We enter all of our basic blocks into a set using the BasicBlock::Less() - // comparator. This naturally results in blocks with identical tails of - // instructions to map to the same entry in the set. Whenever we discover - // that a particular chain of instructions is already in the set, we merge - // the basic blocks and update the pointer in the "blocks" map. - // Returns the number of unique basic blocks. - // N.B. We don't merge instructions on a granularity that is finer than - // a basic block. In practice, this is sufficiently rare that we don't - // incur a big cost. - // Similarly, we currently don't merge anything other than tails. In - // the future, we might decide to revisit this decision and attempt to - // merge arbitrary sub-sequences of instructions. - BasicBlock::Less<TargetsToBlocks> less(*blocks, PointerCompare); - typedef std::set<BasicBlock*, BasicBlock::Less<TargetsToBlocks> > Set; - Set seen_basic_blocks(less); - for (TargetsToBlocks::iterator iter = blocks->begin(); iter != blocks->end(); - ++iter) { - BasicBlock* bb = iter->second; - Set::const_iterator entry = seen_basic_blocks.find(bb); - if (entry == seen_basic_blocks.end()) { - // This is the first time we see this particular sequence of - // instructions. Enter the basic block into the set of known - // basic blocks. - seen_basic_blocks.insert(bb); - } else { - // We have previously seen another basic block that defines the same - // sequence of instructions. Merge the two blocks and update the - // pointer in the "blocks" map. - iter->second = *entry; - } - } -} - -void CodeGen::ComputeIncomingBranches(BasicBlock* block, - const TargetsToBlocks& targets_to_blocks, - IncomingBranches* incoming_branches) { - // We increment the number of incoming branches each time we encounter a - // basic block. But we only traverse recursively the very first time we - // encounter a new block. This is necessary to make topological sorting - // work correctly. - if (++(*incoming_branches)[block] == 1) { - Instruction* last_insn = block->instructions.back(); - if (BPF_CLASS(last_insn->code) == BPF_JMP) { - ComputeIncomingBranches(targets_to_blocks.find(last_insn->jt_ptr)->second, - targets_to_blocks, - incoming_branches); - if (BPF_OP(last_insn->code) != BPF_JA) { - ComputeIncomingBranches( - targets_to_blocks.find(last_insn->jf_ptr)->second, - targets_to_blocks, - incoming_branches); - } - } else if (BPF_CLASS(last_insn->code) != BPF_RET) { - ComputeIncomingBranches(targets_to_blocks.find(last_insn->next)->second, - targets_to_blocks, - incoming_branches); - } - } -} - -void CodeGen::TopoSortBasicBlocks(BasicBlock* first_block, - const TargetsToBlocks& blocks, - BasicBlocks* basic_blocks) { - // Textbook implementation of a toposort. We keep looking for basic blocks - // that don't have any incoming branches (initially, this is just the - // "first_block") and add them to the topologically sorted list of - // "basic_blocks". As we do so, we remove outgoing branches. This potentially - // ends up making our descendants eligible for the sorted list. The - // sorting algorithm terminates when there are no more basic blocks that have - // no incoming branches. If we didn't move all blocks from the set of - // "unordered_blocks" to the sorted list of "basic_blocks", there must have - // been a cyclic dependency. This should never happen in a BPF program, as - // well-formed BPF programs only ever have forward branches. - IncomingBranches unordered_blocks; - ComputeIncomingBranches(first_block, blocks, &unordered_blocks); - - std::set<BasicBlock*> heads; - for (;;) { - // Move block from "unordered_blocks" to "basic_blocks". - basic_blocks->push_back(first_block); - - // Inspect last instruction in the basic block. This is typically either a - // jump or a return statement. But it could also be a "normal" instruction - // that is followed by a jump target. - Instruction* last_insn = first_block->instructions.back(); - if (BPF_CLASS(last_insn->code) == BPF_JMP) { - // Remove outgoing branches. This might end up moving our descendants - // into set of "head" nodes that no longer have any incoming branches. - TargetsToBlocks::const_iterator iter; - if (BPF_OP(last_insn->code) != BPF_JA) { - iter = blocks.find(last_insn->jf_ptr); - if (!--unordered_blocks[iter->second]) { - heads.insert(iter->second); - } - } - iter = blocks.find(last_insn->jt_ptr); - if (!--unordered_blocks[iter->second]) { - first_block = iter->second; - continue; - } - } else if (BPF_CLASS(last_insn->code) != BPF_RET) { - // We encountered an instruction that doesn't change code flow. Try to - // pick the next "first_block" from "last_insn->next", if possible. - TargetsToBlocks::const_iterator iter; - iter = blocks.find(last_insn->next); - if (!--unordered_blocks[iter->second]) { - first_block = iter->second; - continue; - } else { - // Our basic block is supposed to be followed by "last_insn->next", - // but dependencies prevent this from happening. Insert a BPF_JA - // instruction to correct the code flow. - Instruction* ja = MakeInstruction(BPF_JMP + BPF_JA, 0, last_insn->next); - first_block->instructions.push_back(ja); - last_insn->next = ja; - } - } - if (heads.empty()) { - if (unordered_blocks.size() != basic_blocks->size()) { - SANDBOX_DIE("Internal compiler error; cyclic graph detected"); - } - return; - } - // Proceed by picking an arbitrary node from the set of basic blocks that - // do not have any incoming branches. - first_block = *heads.begin(); - heads.erase(heads.begin()); - } -} - -void CodeGen::ComputeRelativeJumps(BasicBlocks* basic_blocks, - const TargetsToBlocks& targets_to_blocks) { - // While we previously used pointers in jt_ptr and jf_ptr to link jump - // instructions to their targets, we now convert these jumps to relative - // jumps that are suitable for loading the BPF program into the kernel. - int offset = 0; - - // Since we just completed a toposort, all jump targets are guaranteed to - // go forward. This means, iterating over the basic blocks in reverse makes - // it trivial to compute the correct offsets. - BasicBlock* bb = NULL; - BasicBlock* last_bb = NULL; - for (BasicBlocks::reverse_iterator iter = basic_blocks->rbegin(); - iter != basic_blocks->rend(); - ++iter) { - last_bb = bb; - bb = *iter; - Instruction* insn = bb->instructions.back(); - if (BPF_CLASS(insn->code) == BPF_JMP) { - // Basic block ended in a jump instruction. We can now compute the - // appropriate offsets. - if (BPF_OP(insn->code) == BPF_JA) { - // "Always" jumps use the 32bit "k" field for the offset, instead - // of the 8bit "jt" and "jf" fields. - int jmp = offset - targets_to_blocks.find(insn->jt_ptr)->second->offset; - insn->k = jmp; - insn->jt = insn->jf = 0; - } else { - // The offset computations for conditional jumps are just the same - // as for "always" jumps. - int jt = offset - targets_to_blocks.find(insn->jt_ptr)->second->offset; - int jf = offset - targets_to_blocks.find(insn->jf_ptr)->second->offset; - - // There is an added complication, because conditional relative jumps - // can only jump at most 255 instructions forward. If we have to jump - // further, insert an extra "always" jump. - Instructions::size_type jmp = bb->instructions.size(); - if (jt > 255 || (jt == 255 && jf > 255)) { - Instruction* ja = MakeInstruction(BPF_JMP + BPF_JA, 0, insn->jt_ptr); - bb->instructions.push_back(ja); - ja->k = jt; - ja->jt = ja->jf = 0; - - // The newly inserted "always" jump, of course, requires us to adjust - // the jump targets in the original conditional jump. - jt = 0; - ++jf; - } - if (jf > 255) { - Instruction* ja = MakeInstruction(BPF_JMP + BPF_JA, 0, insn->jf_ptr); - bb->instructions.insert(bb->instructions.begin() + jmp, ja); - ja->k = jf; - ja->jt = ja->jf = 0; - - // Again, we have to adjust the jump targets in the original - // conditional jump. - ++jt; - jf = 0; - } - - // Now we can finally set the relative jump targets in the conditional - // jump instruction. Afterwards, we must no longer access the jt_ptr - // and jf_ptr fields. - insn->jt = jt; - insn->jf = jf; - } - } else if (BPF_CLASS(insn->code) != BPF_RET && - targets_to_blocks.find(insn->next)->second != last_bb) { - SANDBOX_DIE("Internal compiler error; invalid basic block encountered"); - } - - // Proceed to next basic block. - offset += bb->instructions.size(); - bb->offset = offset; - } - return; -} - -void CodeGen::ConcatenateBasicBlocks(const BasicBlocks& basic_blocks, - Program* program) { - // Our basic blocks have been sorted and relative jump offsets have been - // computed. The last remaining step is for all the instructions in our - // basic blocks to be concatenated into a BPF program. - program->clear(); - for (BasicBlocks::const_iterator bb_iter = basic_blocks.begin(); - bb_iter != basic_blocks.end(); - ++bb_iter) { - const BasicBlock& bb = **bb_iter; - for (Instructions::const_iterator insn_iter = bb.instructions.begin(); - insn_iter != bb.instructions.end(); - ++insn_iter) { - const Instruction& insn = **insn_iter; - program->push_back( - (struct sock_filter) {insn.code, insn.jt, insn.jf, insn.k}); - } - } - return; -} - -void CodeGen::Compile(Instruction* instructions, Program* program) { - if (compiled_) { - SANDBOX_DIE( - "Cannot call Compile() multiple times. Create a new code " - "generator instead"); - } - compiled_ = true; - - BranchTargets branch_targets; - FindBranchTargets(*instructions, &branch_targets); - TargetsToBlocks all_blocks; - BasicBlock* first_block = - CutGraphIntoBasicBlocks(instructions, branch_targets, &all_blocks); - MergeTails(&all_blocks); - BasicBlocks basic_blocks; - TopoSortBasicBlocks(first_block, all_blocks, &basic_blocks); - ComputeRelativeJumps(&basic_blocks, all_blocks); - ConcatenateBasicBlocks(basic_blocks, program); - return; +// TODO(mdempsky): Move into a general base::Tuple helper library. +bool CodeGen::MemoKeyLess::operator()(const MemoKey& lhs, + const MemoKey& rhs) const { + if (lhs.a != rhs.a) + return lhs.a < rhs.a; + if (lhs.b != rhs.b) + return lhs.b < rhs.b; + if (lhs.c != rhs.c) + return lhs.c < rhs.c; + if (lhs.d != rhs.d) + return lhs.d < rhs.d; + return false; } } // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/codegen.h b/sandbox/linux/seccomp-bpf/codegen.h index fd229f7..bca4046 100644 --- a/sandbox/linux/seccomp-bpf/codegen.h +++ b/sandbox/linux/seccomp-bpf/codegen.h
@@ -5,28 +5,23 @@ #ifndef SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ #define SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ +#include <stddef.h> #include <stdint.h> #include <map> #include <vector> +#include "base/macros.h" +#include "base/tuple.h" #include "sandbox/sandbox_export.h" struct sock_filter; namespace sandbox { -struct BasicBlock; -struct Instruction; - -typedef std::vector<Instruction*> Instructions; -typedef std::vector<BasicBlock*> BasicBlocks; -typedef std::map<const Instruction*, int> BranchTargets; -typedef std::map<const Instruction*, BasicBlock*> TargetsToBlocks; -typedef std::map<const BasicBlock*, int> IncomingBranches; // The code generator implements a basic assembler that can convert a // graph of BPF instructions into a well-formed array of BPF -// instructions. Most notably, it ensures that jumps are always +// instructions. Most notably, it ensures that jumps are always // forward and don't exceed the limit of 255 instructions imposed by // the instruction set. // @@ -62,19 +57,18 @@ typedef std::vector<struct sock_filter> Program; // Node represents a node within the instruction DAG being compiled. - // Nodes are owned by the CodeGen object and need not be explicitly - // deleted. - using Node = Instruction*; + using Node = Program::size_type; // kNullNode represents the "null" node; i.e., the reserved node // value guaranteed to not equal any actual nodes. - static const Node kNullNode; + static const Node kNullNode = -1; CodeGen(); ~CodeGen(); // MakeInstruction creates a node representing the specified - // instruction. For details on the possible parameters refer to + // instruction, or returns and existing equivalent node if one + // exists. For details on the possible parameters refer to // https://www.kernel.org/doc/Documentation/networking/filter.txt. // TODO(mdempsky): Reconsider using default arguments here. Node MakeInstruction(uint16_t code, @@ -82,72 +76,39 @@ Node jt = kNullNode, Node jf = kNullNode); - // Compile linearizes the instruction DAG into a BPF program that - // can be executed by a BPF virtual machine. Please note that this - // function modifies the graph in place and must therefore only be - // called once per graph. + // Compile linearizes the instruction DAG rooted at |head| into a + // program that can be executed by a BPF virtual machine. void Compile(Node head, Program* program); private: - friend class CodeGenUnittestHelper; + using MemoKey = Tuple4<uint16_t, uint32_t, Node, Node>; + struct MemoKeyLess { + bool operator()(const MemoKey& lhs, const MemoKey& rhs) const; + }; - // Find all the instructions that are the target of BPF_JMPs. - void FindBranchTargets(const Instruction& instructions, - BranchTargets* branch_targets); + // AppendInstruction adds a new instruction, ensuring that |jt| and + // |jf| are within range as necessary for |code|. + Node AppendInstruction(uint16_t code, uint32_t k, Node jt, Node jf); - // Combine instructions between "head" and "tail" into a new basic block. - // Basic blocks are defined as sequences of instructions whose only branch - // target is the very first instruction; furthermore, any BPF_JMP or BPF_RET - // instruction must be at the very end of the basic block. - BasicBlock* MakeBasicBlock(Instruction* head, Instruction* tail); + // WithinRange returns a node equivalent to |next| that is at most + // |range| instructions away from the (logical) beginning of the + // program. + Node WithinRange(Node next, size_t range); - // Creates a basic block and adds it to "basic_blocks"; sets "first_block" - // if it is still NULL. - void AddBasicBlock(Instruction* head, - Instruction* tail, - const BranchTargets& branch_targets, - TargetsToBlocks* basic_blocks, - BasicBlock** first_block); + // Append appends a new instruction to the physical end (i.e., + // logical beginning) of |program_|. + Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf); - // Cuts the DAG of instructions into basic blocks. - BasicBlock* CutGraphIntoBasicBlocks(Instruction* instructions, - const BranchTargets& branch_targets, - TargetsToBlocks* blocks); + // Offset returns how many instructions exist in |program_| after |target|. + size_t Offset(Node target) const; - // Find common tail sequences of basic blocks and coalesce them. - void MergeTails(TargetsToBlocks* blocks); + // NOTE: program_ is the compiled program in *reverse*, so that + // indices remain stable as we add instructions. + Program program_; - // For each basic block, compute the number of incoming branches. - void ComputeIncomingBranches(BasicBlock* block, - const TargetsToBlocks& targets_to_blocks, - IncomingBranches* incoming_branches); + std::map<MemoKey, Node, MemoKeyLess> memos_; - // Topologically sort the basic blocks so that all jumps are forward jumps. - // This is a requirement for any well-formed BPF program. - void TopoSortBasicBlocks(BasicBlock* first_block, - const TargetsToBlocks& blocks, - BasicBlocks* basic_blocks); - - // Convert jt_ptr_ and jf_ptr_ fields in BPF_JMP instructions to valid - // jt_ and jf_ jump offsets. This can result in BPF_JA instructions being - // inserted, if we need to jump over more than 256 instructions. - void ComputeRelativeJumps(BasicBlocks* basic_blocks, - const TargetsToBlocks& targets_to_blocks); - - // Concatenate instructions from all basic blocks into a BPF program that - // can be passed to the kernel. - void ConcatenateBasicBlocks(const BasicBlocks&, Program* program); - - // We stick all instructions and basic blocks into pools that get destroyed - // when the CodeGen object is destroyed. This way, we neither need to worry - // about explicitly managing ownership, nor do we need to worry about using - // smart pointers in the presence of circular references. - Instructions instructions_; - BasicBlocks basic_blocks_; - - // Compile() must only ever be called once as it makes destructive changes - // to the DAG. - bool compiled_; + DISALLOW_COPY_AND_ASSIGN(CodeGen); }; } // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/codegen_unittest.cc b/sandbox/linux/seccomp-bpf/codegen_unittest.cc index 3f1a04b..a001668 100644 --- a/sandbox/linux/seccomp-bpf/codegen_unittest.cc +++ b/sandbox/linux/seccomp-bpf/codegen_unittest.cc
@@ -116,13 +116,7 @@ CodeGen::Node res = gen_.MakeInstruction(code, k, jt, jf); EXPECT_NE(CodeGen::kNullNode, res); - Hash digest; - if (code == BPF_JMP + BPF_JA) { - // TODO(mdempsky): Disallow use of JA. - digest = Lookup(jt); - } else { - digest = Hash(code, k, Lookup(jt), Lookup(jf)); - } + Hash digest(code, k, Lookup(jt), Lookup(jf)); auto it = node_hashes_.insert(std::make_pair(res, digest)); EXPECT_EQ(digest, it.first->second); @@ -224,12 +218,12 @@ // RET 42 (insn3+) CodeGen::Node insn0 = MakeInstruction(BPF_RET + BPF_K, 42); CodeGen::Node insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0); - CodeGen::Node insn2 = MakeInstruction(BPF_JMP + BPF_JA, 0, insn1); + CodeGen::Node insn2 = insn1; // Implicit JUMP - // We explicitly duplicate instructions so that MergeTails() can coalesce - // them later. + // We explicitly duplicate instructions to test that they're merged. CodeGen::Node insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, MakeInstruction(BPF_RET + BPF_K, 42)); + EXPECT_EQ(insn2, insn3); CodeGen::Node insn4 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3); @@ -328,5 +322,50 @@ RunTest(i0); } +TEST_F(ProgramTest, InstructionFolding) { + // Check that simple instructions are folded as expected. + CodeGen::Node a = MakeInstruction(BPF_RET + BPF_K, 0); + EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0)); + CodeGen::Node b = MakeInstruction(BPF_RET + BPF_K, 1); + EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0)); + EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1)); + EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1)); + + // Check that complex sequences are folded too. + CodeGen::Node c = + MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, + MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b)); + EXPECT_EQ(c, MakeInstruction( + BPF_LD + BPF_W + BPF_ABS, 0, + MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b))); + + RunTest(c); +} + +TEST_F(ProgramTest, FarBranches) { + // BPF instructions use 8-bit fields for branch offsets, which means + // branch targets must be within 255 instructions of the branch + // instruction. CodeGen abstracts away this detail by inserting jump + // instructions as needed, which we test here by generating programs + // that should trigger any interesting boundary conditions. + + // Populate with 260 initial instruction nodes. + std::vector<CodeGen::Node> nodes; + nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0)); + for (size_t i = 1; i < 260; ++i) { + nodes.push_back( + MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back())); + } + + // Exhaustively test branch offsets near BPF's limits. + for (size_t jt = 250; jt < 260; ++jt) { + for (size_t jf = 250; jf < 260; ++jf) { + nodes.push_back(MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0, + nodes.rbegin()[jt], nodes.rbegin()[jf])); + RunTest(nodes.back()); + } + } +} + } // namespace } // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/instruction.h b/sandbox/linux/seccomp-bpf/instruction.h deleted file mode 100644 index 70b7791..0000000 --- a/sandbox/linux/seccomp-bpf/instruction.h +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SANDBOX_LINUX_SECCOMP_BPF_INSTRUCTION_H__ -#define SANDBOX_LINUX_SECCOMP_BPF_INSTRUCTION_H__ - -#include <stdint.h> - -#include <cstddef> - -namespace sandbox { - -// The fields in this structure have the same meaning as the corresponding -// fields in "struct sock_filter". See <linux/filter.h> for a lot more -// detail. -// code -- Opcode of the instruction. This is typically a bitwise -// combination BPF_XXX values. -// k -- Operand; BPF instructions take zero or one operands. Operands -// are 32bit-wide constants, if present. They can be immediate -// values (if BPF_K is present in "code_"), addresses (if BPF_ABS -// is present in "code_"), or relative jump offsets (if BPF_JMP -// and BPF_JA are present in "code_"). -// jt, jf -- all conditional jumps have a 8bit-wide jump offset that allows -// jumps of up to 256 instructions forward. Conditional jumps are -// identified by BPF_JMP in "code_", but the lack of BPF_JA. -// Conditional jumps have a "t"rue and "f"alse branch. -struct Instruction { - // Constructor for an non-jumping instruction or for an unconditional - // "always" jump. - Instruction(uint16_t c, uint32_t parm, Instruction* n) - : code(c), jt(0), jf(0), jt_ptr(NULL), jf_ptr(NULL), next(n), k(parm) {} - - // Constructor for a conditional jump instruction. - Instruction(uint16_t c, uint32_t parm, Instruction* jt, Instruction* jf) - : code(c), jt(0), jf(0), jt_ptr(jt), jf_ptr(jf), next(NULL), k(parm) {} - - uint16_t code; - - // When code generation is complete, we will have computed relative - // branch targets that are in the range 0..255. - uint8_t jt, jf; - - // While assembling the BPF program, we use pointers for branch targets. - // Once we have computed basic blocks, these pointers will be entered as - // keys in a TargetsToBlocks map and should no longer be dereferenced - // directly. - Instruction* jt_ptr, *jf_ptr; - - // While assembling the BPF program, non-jumping instructions are linked - // by the "next_" pointer. This field is no longer needed when we have - // computed basic blocks. - Instruction* next; - - uint32_t k; -}; - -} // namespace sandbox - -#endif // SANDBOX_LINUX_SECCOMP_BPF_INSTRUCTION_H__
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc index d5a5d4d..43c9af6 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -41,6 +41,7 @@ #include "sandbox/linux/seccomp-bpf/trap.h" #include "sandbox/linux/seccomp-bpf/verifier.h" #include "sandbox/linux/services/linux_syscalls.h" +#include "sandbox/linux/services/syscall_wrappers.h" using sandbox::bpf_dsl::Allow; using sandbox::bpf_dsl::Error; @@ -92,8 +93,8 @@ }; void ProbeProcess(void) { - if (syscall(__NR_getpid) < 0 && errno == EPERM) { - syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode)); + if (sys_getpid() < 0 && errno == EPERM) { + sys_exit_group(kExpectedExitCode); } } @@ -117,7 +118,7 @@ // vsyscall=emulate and some versions of the seccomp BPF patch // we may get SIGKILL-ed. Detect this! if (time(¤t_time) != static_cast<time_t>(-1)) { - syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode)); + sys_exit_group(kExpectedExitCode); } }
diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc index 96702b1..a745220 100644 --- a/sandbox/linux/services/credentials.cc +++ b/sandbox/linux/services/credentials.cc
@@ -24,6 +24,7 @@ #include "base/template_util.h" #include "base/third_party/valgrind/valgrind.h" #include "base/threading/thread.h" +#include "sandbox/linux/services/syscall_wrappers.h" namespace { @@ -286,7 +287,7 @@ } // This is roughly a fork(). - const pid_t pid = syscall(__NR_clone, CLONE_NEWUSER | SIGCHLD, 0, 0, 0); + const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0); if (pid == -1) { CheckCloneNewUserErrno(errno);
diff --git a/sandbox/linux/services/scoped_process.cc b/sandbox/linux/services/scoped_process.cc index fd42a2a..bdeaee9 100644 --- a/sandbox/linux/services/scoped_process.cc +++ b/sandbox/linux/services/scoped_process.cc
@@ -17,6 +17,7 @@ #include "base/logging.h" #include "base/posix/eintr_wrapper.h" #include "build/build_config.h" +#include "sandbox/linux/services/syscall_wrappers.h" #include "sandbox/linux/services/thread_helpers.h" namespace sandbox { @@ -112,7 +113,7 @@ // This method allows to assert it is not happening. bool ScopedProcess::IsOriginalProcess() { // Make a direct syscall to bypass glibc caching of PIDs. - int pid = syscall(__NR_getpid); + pid_t pid = sys_getpid(); return pid == process_id_; }
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc new file mode 100644 index 0000000..3938694 --- /dev/null +++ b/sandbox/linux/services/syscall_wrappers.cc
@@ -0,0 +1,59 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/linux/services/syscall_wrappers.h" + +#include <sys/syscall.h> +#include <sys/types.h> +#include <unistd.h> + +#include "base/logging.h" +#include "build/build_config.h" +#include "sandbox/linux/services/linux_syscalls.h" + +namespace sandbox { + +pid_t sys_getpid(void) { + return syscall(__NR_getpid); +} + +pid_t sys_gettid(void) { + return syscall(__NR_gettid); +} + +long sys_clone(unsigned long flags) { + return sys_clone(flags, nullptr, nullptr, nullptr, nullptr); +} + +long sys_clone(unsigned long flags, + void* child_stack, + pid_t* ptid, + pid_t* ctid, + decltype(nullptr) tls) { + const bool clone_tls_used = flags & CLONE_SETTLS; + const bool invalid_ctid = + (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid; + const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid; + const bool invalid_stack = (flags & CLONE_VM) && !child_stack; + + if (clone_tls_used || invalid_ctid || invalid_ptid || invalid_stack) { + RAW_LOG(FATAL, "Invalid usage of sys_clone"); + } + +// See kernel/fork.c in Linux. There is different ordering of sys_clone +// parameters depending on CONFIG_CLONE_BACKWARDS* configuration options. +#if defined(ARCH_CPU_X86_64) + return syscall(__NR_clone, flags, child_stack, ptid, ctid, tls); +#elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \ + defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY) + // CONFIG_CLONE_BACKWARDS defined. + return syscall(__NR_clone, flags, child_stack, ptid, tls, ctid); +#endif +} + +void sys_exit_group(int status) { + syscall(__NR_exit_group, status); +} + +} // namespace sandbox
diff --git a/sandbox/linux/services/syscall_wrappers.h b/sandbox/linux/services/syscall_wrappers.h new file mode 100644 index 0000000..03d5cdf --- /dev/null +++ b/sandbox/linux/services/syscall_wrappers.h
@@ -0,0 +1,35 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_ +#define SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_ + +#include <sys/types.h> + +#include "sandbox/sandbox_export.h" + +namespace sandbox { + +// Provide direct system call wrappers for a few common system calls. +// These are guaranteed to perform a system call and do not rely on things such +// as caching the current pid (c.f. getpid()). + +SANDBOX_EXPORT pid_t sys_getpid(void); + +SANDBOX_EXPORT pid_t sys_gettid(void); + +SANDBOX_EXPORT long sys_clone(unsigned long flags); + +// |regs| is not supported and must be passed as nullptr. +SANDBOX_EXPORT long sys_clone(unsigned long flags, + void* child_stack, + pid_t* ptid, + pid_t* ctid, + decltype(nullptr) regs); + +SANDBOX_EXPORT void sys_exit_group(int status); + +} // namespace sandbox + +#endif // SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
diff --git a/sandbox/linux/services/syscall_wrappers_unittest.cc b/sandbox/linux/services/syscall_wrappers_unittest.cc new file mode 100644 index 0000000..861dd5f --- /dev/null +++ b/sandbox/linux/services/syscall_wrappers_unittest.cc
@@ -0,0 +1,63 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/linux/services/syscall_wrappers.h" + +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "build/build_config.h" +#include "sandbox/linux/tests/test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace sandbox { + +namespace { + +TEST(SyscallWrappers, BasicSyscalls) { + EXPECT_EQ(getpid(), sys_getpid()); +} + +TEST(SyscallWrappers, CloneBasic) { + pid_t child = sys_clone(SIGCHLD); + TestUtils::HandlePostForkReturn(child); + EXPECT_LT(0, child); +} + +TEST(SyscallWrappers, CloneParentSettid) { + pid_t ptid = 0; + pid_t child = sys_clone(CLONE_PARENT_SETTID | SIGCHLD, nullptr, &ptid, + nullptr, nullptr); + TestUtils::HandlePostForkReturn(child); + EXPECT_LT(0, child); + EXPECT_EQ(child, ptid); +} + +TEST(SyscallWrappers, CloneChildSettid) { + pid_t ctid = 0; + pid_t pid = + sys_clone(CLONE_CHILD_SETTID | SIGCHLD, nullptr, nullptr, &ctid, nullptr); + + const int kSuccessExit = 0; + if (0 == pid) { + // In child. + if (sys_getpid() == ctid) + _exit(kSuccessExit); + _exit(1); + } + + ASSERT_NE(-1, pid); + int status = 0; + ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0))); + ASSERT_TRUE(WIFEXITED(status)); + EXPECT_EQ(kSuccessExit, WEXITSTATUS(status)); +} + +} // namespace + +} // namespace sandbox
diff --git a/sandbox/linux/services/unix_domain_socket_unittest.cc b/sandbox/linux/services/unix_domain_socket_unittest.cc index 17208a8..4d57c0d 100644 --- a/sandbox/linux/services/unix_domain_socket_unittest.cc +++ b/sandbox/linux/services/unix_domain_socket_unittest.cc
@@ -18,6 +18,7 @@ #include "base/posix/eintr_wrapper.h" #include "base/posix/unix_domain_socket_linux.h" #include "base/process/process_handle.h" +#include "sandbox/linux/services/syscall_wrappers.h" #include "sandbox/linux/tests/unit_tests.h" // Additional tests for base's UnixDomainSocket to make sure it behaves @@ -144,14 +145,14 @@ CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get())); - const pid_t pid = syscall(__NR_clone, CLONE_NEWPID | SIGCHLD, 0, 0, 0); + const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0); CHECK_NE(-1, pid); if (pid == 0) { // Child process. recv_sock.reset(); // Check that we think we're pid 1 in our new namespace. - CHECK_EQ(1, syscall(__NR_getpid)); + CHECK_EQ(1, sys_getpid()); SendHello(send_sock.get()); _exit(0); @@ -178,13 +179,13 @@ CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get())); - const pid_t pid = syscall(__NR_clone, CLONE_NEWPID | SIGCHLD, 0, 0, 0); + const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0); CHECK_NE(-1, pid); if (pid == 0) { // Child process. recv_sock.reset(); - const pid_t pid2 = syscall(__NR_clone, CLONE_NEWPID | SIGCHLD, 0, 0, 0); + const pid_t pid2 = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0); CHECK_NE(-1, pid2); if (pid2 != 0) { @@ -195,7 +196,7 @@ } // Check that we think we're pid 1. - CHECK_EQ(1, syscall(__NR_getpid)); + CHECK_EQ(1, sys_getpid()); SendHello(send_sock.get()); _exit(0); @@ -244,7 +245,7 @@ CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get())); - const pid_t pid = syscall(__NR_clone, CLONE_NEWPID | SIGCHLD, 0, 0, 0); + const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0); CHECK_NE(-1, pid); if (pid == 0) { // Child process.
diff --git a/sandbox/linux/tests/test_utils.cc b/sandbox/linux/tests/test_utils.cc index 398654b..6000b8a 100644 --- a/sandbox/linux/tests/test_utils.cc +++ b/sandbox/linux/tests/test_utils.cc
@@ -28,4 +28,16 @@ } } +void TestUtils::HandlePostForkReturn(pid_t pid) { + const int kChildExitCode = 1; + if (pid > 0) { + int status = 0; + PCHECK(pid == HANDLE_EINTR(waitpid(pid, &status, 0))); + CHECK(WIFEXITED(status)); + CHECK_EQ(kChildExitCode, WEXITSTATUS(status)); + } else if (pid == 0) { + _exit(kChildExitCode); + } +} + } // namespace sandbox
diff --git a/sandbox/linux/tests/test_utils.h b/sandbox/linux/tests/test_utils.h index 3269847..1d9eb79 100644 --- a/sandbox/linux/tests/test_utils.h +++ b/sandbox/linux/tests/test_utils.h
@@ -5,6 +5,8 @@ #ifndef SANDBOX_LINUX_TESTS_TEST_UTILS_H_ #define SANDBOX_LINUX_TESTS_TEST_UTILS_H_ +#include <sys/types.h> + #include "base/basictypes.h" namespace sandbox { @@ -13,6 +15,10 @@ class TestUtils { public: static bool CurrentProcessHasChildren(); + // |pid| is the return value of a fork()-like call. This + // makes sure that if fork() succeeded the child exits + // and the parent waits for it. + static void HandlePostForkReturn(pid_t pid); private: DISALLOW_IMPLICIT_CONSTRUCTORS(TestUtils);
diff --git a/sandbox/linux/tests/test_utils_unittest.cc b/sandbox/linux/tests/test_utils_unittest.cc new file mode 100644 index 0000000..0f86e61 --- /dev/null +++ b/sandbox/linux/tests/test_utils_unittest.cc
@@ -0,0 +1,24 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/linux/tests/test_utils.h" + +#include <sys/types.h> +#include <unistd.h> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace sandbox { + +namespace { + +// Check that HandlePostForkReturn works. +TEST(TestUtils, HandlePostForkReturn) { + pid_t pid = fork(); + TestUtils::HandlePostForkReturn(pid); +} + +} // namespace + +} // namespace sandbox
diff --git a/skia/skia_library.gypi b/skia/skia_library.gypi index 46259e5..7d369d8 100644 --- a/skia/skia_library.gypi +++ b/skia/skia_library.gypi
@@ -360,6 +360,13 @@ ['include', 'SkStream_mac\\.cpp$',], ['include', 'SkCreateCGImageRef\\.cpp$',], ], + 'xcode_settings' : { + 'WARNING_CFLAGS': [ + # SkFontHost_mac.cpp uses API deprecated in iOS 7. + # crbug.com/408571 + '-Wno-deprecated-declarations', + ], + }, }], ],
diff --git a/testing/android/junit/javatests/src/org/chromium/testing/local/GtestLoggerTest.java b/testing/android/junit/javatests/src/org/chromium/testing/local/GtestLoggerTest.java index 2a442fc..2bb3040 100644 --- a/testing/android/junit/javatests/src/org/chromium/testing/local/GtestLoggerTest.java +++ b/testing/android/junit/javatests/src/org/chromium/testing/local/GtestLoggerTest.java
@@ -43,8 +43,8 @@ Description.createTestDescription(GtestLoggerTest.class, "testTestFinishedPassed"), true, 123); Assert.assertEquals( - "[ OK ] org.chromium.testing.local.GtestLoggerTest.testTestFinishedPassed" + - " (123 ms)\n", + "[ OK ] org.chromium.testing.local.GtestLoggerTest.testTestFinishedPassed" + + " (123 ms)\n", actual.toString()); } @@ -56,8 +56,8 @@ Description.createTestDescription(GtestLoggerTest.class, "testTestFinishedPassed"), false, 123); Assert.assertEquals( - "[ FAILED ] org.chromium.testing.local.GtestLoggerTest.testTestFinishedPassed" + - " (123 ms)\n", + "[ FAILED ] org.chromium.testing.local.GtestLoggerTest.testTestFinishedPassed" + + " (123 ms)\n", actual.toString()); } @@ -79,8 +79,8 @@ loggerUnderTest.testCaseFinished( Description.createSuiteDescription(GtestLoggerTest.class), 456, 123); Assert.assertEquals( - "[----------] Run 456 test cases from org.chromium.testing.local.GtestLoggerTest" + - " (123 ms)\n\n", + "[----------] Run 456 test cases from org.chromium.testing.local.GtestLoggerTest" + + " (123 ms)\n\n", actual.toString()); } @@ -90,8 +90,8 @@ GtestLogger loggerUnderTest = new GtestLogger(new PrintStream(actual)); loggerUnderTest.testRunStarted(1234); Assert.assertEquals( - "[==========] Running 1234 tests.\n" + - "[----------] Global test environment set-up.\n\n", + "[==========] Running 1234 tests.\n" + + "[----------] Global test environment set-up.\n\n", actual.toString()); } @@ -101,9 +101,9 @@ GtestLogger loggerUnderTest = new GtestLogger(new PrintStream(actual)); loggerUnderTest.testRunFinished(1234, new HashSet<Description>(), 4321); Assert.assertEquals( - "[----------] Global test environment tear-down.\n" + - "[==========] 1234 tests ran. (4321 ms total)\n" + - "[ PASSED ] 1234 tests.\n", + "[----------] Global test environment tear-down.\n" + + "[==========] 1234 tests ran. (4321 ms total)\n" + + "[ PASSED ] 1234 tests.\n", actual.toString()); } @@ -120,13 +120,13 @@ loggerUnderTest.testRunFinished(1232, failures, 4312); Assert.assertEquals( - "[----------] Global test environment tear-down.\n" + - "[==========] 1234 tests ran. (4312 ms total)\n" + - "[ PASSED ] 1232 tests.\n" + - "[ FAILED ] 2 tests.\n" + - "[ FAILED ] GtestLoggerTest.testTestRunFinishedNoFailures\n" + - "[ FAILED ] GtestLoggerTest.testTestRunFinishedWithFailures\n" + - "\n", + "[----------] Global test environment tear-down.\n" + + "[==========] 1234 tests ran. (4312 ms total)\n" + + "[ PASSED ] 1232 tests.\n" + + "[ FAILED ] 2 tests.\n" + + "[ FAILED ] GtestLoggerTest.testTestRunFinishedNoFailures\n" + + "[ FAILED ] GtestLoggerTest.testTestRunFinishedWithFailures\n" + + "\n", actual.toString()); }
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index a2a9b23..70393de 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -61,6 +61,7 @@ "args": ["--test-launcher-print-test-stdio=always"] }, "ui_base_unittests", + "ui_chromeos_unittests", "views_unittests", "wm_unittests", "aura_unittests", @@ -133,6 +134,7 @@ "sql_unittests", "sync_unit_tests", "ui_base_unittests", + "ui_chromeos_unittests", "unit_tests", "url_unittests", "views_unittests", @@ -180,6 +182,7 @@ "args": ["--test-launcher-print-test-stdio=always"] }, "ui_base_unittests", + "ui_chromeos_unittests", "views_unittests", "wm_unittests", "aura_unittests",
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index bee8677..3c54f1b 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -353,6 +353,12 @@ { "test": "content_browsertests", "args": ["--site-per-process", "--gtest_filter=-*.AllowTargetedNavigationsAfterSwap:*.SupportCrossProcessPostMessage:*.DontSwapProcessWithOnlyTargetBlank:*.DisownOpener:*.NavigateWithLeftoverFrames:*.DontPreemptNavigationWithFrameTreeUpdate:*.ProcessExitWithSwappedOutViews:*.SupportCrossProcessPostMessageWithMessagePort:*.AllowTargetedNavigationsInOpenerAfterSwap"] } ] }, + "Browser Side Navigation Linux": { + "gtest_tests": [ + { "test": "content_unittests", "args": ["--enable-browser-side-navigation"] }, + { "test": "content_browsertests", "args": ["--enable-browser-side-navigation"] } + ] + }, "Linux ChromeOS MSan Tests": { "gtest_tests": [ "accessibility_unittests",
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 8f72e65..9987ad7 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -304,6 +304,7 @@ } }, "ui_base_unittests", + "ui_chromeos_unittests", "url_unittests", "views_unittests" ]
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json index 6e3cff5..4b6de77 100644 --- a/testing/buildbot/chromium_trybot.json +++ b/testing/buildbot/chromium_trybot.json
@@ -165,6 +165,15 @@ "shards": 2 } }, + { + "test": "ui_chromeos_unittests", + "platforms": ["linux"], + "chromium_configs": [ + "chromium_chromeos", + "chromium_chromeos_clang", + "chromium_chromeos_ozone" + ] + }, "url_unittests", { "test": "wm_unittests",
diff --git a/third_party/android_testrunner/README.chromium b/third_party/android_testrunner/README.chromium index 7d382a1..6ca8498 100644 --- a/third_party/android_testrunner/README.chromium +++ b/third_party/android_testrunner/README.chromium
@@ -18,6 +18,8 @@ bugs in run_command.py. 4. Fixed a bug where wait_time wasn't properly respected in _WaitForShellCommandContents. +5. Added option to specify the ADB binary that should be used instead of always + using the ADB in the environment path. Here is the detail steps 1. Checkout Android source code
diff --git a/third_party/android_testrunner/adb_interface.py b/third_party/android_testrunner/adb_interface.py index 93e1963..306f186 100644 --- a/third_party/android_testrunner/adb_interface.py +++ b/third_party/android_testrunner/adb_interface.py
@@ -34,11 +34,19 @@ class AdbInterface: """Helper class for communicating with Android device via adb.""" - # argument to pass to adb, to direct command to specific device - _target_arg = "" - DEVICE_TRACE_DIR = "/data/test_results/" + def __init__(self, adb_path='adb'): + """Constructor. + + Args: + adb_path: Absolute path to the adb binary that should be used. Defaults + to the adb in the environment path. + """ + self._adb_path = adb_path + # argument to pass to adb, to direct command to specific device + self._target_arg = "" + def SetEmulatorTarget(self): """Direct all future commands to the only running emulator.""" self._target_arg = "-e" @@ -66,7 +74,7 @@ Raises: WaitForResponseTimedOutError if device does not respond to command within time """ - adb_cmd = "adb %s %s" % (self._target_arg, command_string) + adb_cmd = "%s %s %s" % (self._adb_path, self._target_arg, command_string) logger.SilentLog("about to run %s" % adb_cmd) return run_command.RunCommand(adb_cmd, timeout_time=timeout_time, retry_count=retry_count)
diff --git a/third_party/checkstyle/README.chromium b/third_party/checkstyle/README.chromium index 53a267c..0ceef78 100644 --- a/third_party/checkstyle/README.chromium +++ b/third_party/checkstyle/README.chromium
@@ -2,7 +2,7 @@ adheres to a coding standard. Short Name: checkstyle URL: http://checkstyle.sourceforge.net/ -Version: 5.9 +Version: 6.1 License: LGPL 2.1 License File: LICENSE Security Critical: no @@ -11,16 +11,5 @@ Checkstyle is used to validate Java code style on Chromium PRESUBMIT step. Local Modifications: -- Removed contrib/ and site/ directories that contained examples of how to write - new checkstyle modules. -- Removed xml files used for Eclipse setup when building new checkstyle modules. - - checkstyle_checks.xml - - import-control.xml - - supressions.xml -- Removed jars already included in checkstyle-5.9-all.jar - - antlr-2.7.7.jar - - checkstyle-5.9.jar - - commons-beanutils-core-1.8.3.jar - - commons-cli-1.2.jar - - commons-logging-1.1.1.jar - - guava-jdk5-14.0.1.jar +- Downloaded checkstyle-6.1-all.jar without source code development + documentation.
diff --git a/third_party/checkstyle/checkstyle-5.9-all.jar b/third_party/checkstyle/checkstyle-5.9-all.jar deleted file mode 100644 index a820e2e..0000000 --- a/third_party/checkstyle/checkstyle-5.9-all.jar +++ /dev/null Binary files differ
diff --git a/third_party/checkstyle/checkstyle-6.1-all.jar b/third_party/checkstyle/checkstyle-6.1-all.jar new file mode 100644 index 0000000..70c272b --- /dev/null +++ b/third_party/checkstyle/checkstyle-6.1-all.jar Binary files differ
diff --git a/third_party/checkstyle/sun_checks.xml b/third_party/checkstyle/sun_checks.xml deleted file mode 100644 index 709f3ec..0000000 --- a/third_party/checkstyle/sun_checks.xml +++ /dev/null
@@ -1,177 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE module PUBLIC - "-//Puppy Crawl//DTD Check Configuration 1.3//EN" - "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> - -<!-- - - Checkstyle configuration that checks the sun coding conventions from: - - - the Java Language Specification at - http://java.sun.com/docs/books/jls/second_edition/html/index.html - - - the Sun Code Conventions at http://java.sun.com/docs/codeconv/ - - - the Javadoc guidelines at - http://java.sun.com/j2se/javadoc/writingdoccomments/index.html - - - the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html - - - some best practices - - Checkstyle is very configurable. Be sure to read the documentation at - http://checkstyle.sf.net (or in your downloaded distribution). - - Most Checks are configurable, be sure to consult the documentation. - - To completely disable a check, just comment it out or delete it from the file. - - Finally, it is worth reading the documentation. - ---> - -<module name="Checker"> - <!-- - If you set the basedir property below, then all reported file - names will be relative to the specified directory. See - http://checkstyle.sourceforge.net/5.x/config.html#Checker - - <property name="basedir" value="${basedir}"/> - --> - - <!-- Checks that a package-info.java file exists for each package. --> - <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage --> - <module name="JavadocPackage"/> - - <!-- Checks whether files end with a new line. --> - <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile --> - <module name="NewlineAtEndOfFile"/> - - <!-- Checks that property files contain the same keys. --> - <!-- See http://checkstyle.sf.net/config_misc.html#Translation --> - <module name="Translation"/> - - <!-- Checks for Size Violations. --> - <!-- See http://checkstyle.sf.net/config_sizes.html --> - <module name="FileLength"/> - - <!-- Checks for whitespace --> - <!-- See http://checkstyle.sf.net/config_whitespace.html --> - <module name="FileTabCharacter"/> - - <!-- Miscellaneous other checks. --> - <!-- See http://checkstyle.sf.net/config_misc.html --> - <module name="RegexpSingleline"> - <property name="format" value="\s+$"/> - <property name="minimum" value="0"/> - <property name="maximum" value="0"/> - <property name="message" value="Line has trailing spaces."/> - </module> - - <!-- Checks for Headers --> - <!-- See http://checkstyle.sf.net/config_header.html --> - <!-- <module name="Header"> --> - <!-- <property name="headerFile" value="${checkstyle.header.file}"/> --> - <!-- <property name="fileExtensions" value="java"/> --> - <!-- </module> --> - - <module name="TreeWalker"> - - <!-- Checks for Javadoc comments. --> - <!-- See http://checkstyle.sf.net/config_javadoc.html --> - <module name="JavadocMethod"/> - <module name="JavadocType"/> - <module name="JavadocVariable"/> - <module name="JavadocStyle"/> - - - <!-- Checks for Naming Conventions. --> - <!-- See http://checkstyle.sf.net/config_naming.html --> - <module name="ConstantName"/> - <module name="LocalFinalVariableName"/> - <module name="LocalVariableName"/> - <module name="MemberName"/> - <module name="MethodName"/> - <module name="PackageName"/> - <module name="ParameterName"/> - <module name="StaticVariableName"/> - <module name="TypeName"/> - - - <!-- Checks for imports --> - <!-- See http://checkstyle.sf.net/config_import.html --> - <module name="AvoidStarImport"/> - <module name="IllegalImport"/> <!-- defaults to sun.* packages --> - <module name="RedundantImport"/> - <module name="UnusedImports"/> - - - <!-- Checks for Size Violations. --> - <!-- See http://checkstyle.sf.net/config_sizes.html --> - <module name="LineLength"/> - <module name="MethodLength"/> - <module name="ParameterNumber"/> - - - <!-- Checks for whitespace --> - <!-- See http://checkstyle.sf.net/config_whitespace.html --> - <module name="EmptyForIteratorPad"/> - <module name="GenericWhitespace"/> - <module name="MethodParamPad"/> - <module name="NoWhitespaceAfter"/> - <module name="NoWhitespaceBefore"/> - <module name="OperatorWrap"/> - <module name="ParenPad"/> - <module name="TypecastParenPad"/> - <module name="WhitespaceAfter"/> - <module name="WhitespaceAround"/> - - - <!-- Modifier Checks --> - <!-- See http://checkstyle.sf.net/config_modifiers.html --> - <module name="ModifierOrder"/> - <module name="RedundantModifier"/> - - - <!-- Checks for blocks. You know, those {}'s --> - <!-- See http://checkstyle.sf.net/config_blocks.html --> - <module name="AvoidNestedBlocks"/> - <module name="EmptyBlock"/> - <module name="LeftCurly"/> - <module name="NeedBraces"/> - <module name="RightCurly"/> - - - <!-- Checks for common coding problems --> - <!-- See http://checkstyle.sf.net/config_coding.html --> - <module name="AvoidInlineConditionals"/> - <module name="EmptyStatement"/> - <module name="EqualsHashCode"/> - <module name="HiddenField"/> - <module name="IllegalInstantiation"/> - <module name="InnerAssignment"/> - <module name="MagicNumber"/> - <module name="MissingSwitchDefault"/> - <module name="RedundantThrows"/> - <module name="SimplifyBooleanExpression"/> - <module name="SimplifyBooleanReturn"/> - - <!-- Checks for class design --> - <!-- See http://checkstyle.sf.net/config_design.html --> - <module name="DesignForExtension"/> - <module name="FinalClass"/> - <module name="HideUtilityClassConstructor"/> - <module name="InterfaceIsType"/> - <module name="VisibilityModifier"/> - - - <!-- Miscellaneous other checks. --> - <!-- See http://checkstyle.sf.net/config_misc.html --> - <module name="ArrayTypeStyle"/> - <module name="FinalParameters"/> - <module name="TodoComment"/> - <module name="UpperEll"/> - - </module> - -</module>
diff --git a/third_party/cython/rules.gni b/third_party/cython/rules.gni index 252e948..efd9ca3 100644 --- a/third_party/cython/rules.gni +++ b/third_party/cython/rules.gni
@@ -76,6 +76,9 @@ sources += invoker.additional_sources } configs += [ ":$config_name" ] + if (defined(invoker.configs)) { + configs += invoker.configs + } } copy(target_name) {
diff --git a/third_party/harfbuzz-ng/harfbuzz.gyp b/third_party/harfbuzz-ng/harfbuzz.gyp index 3e6fed4..96e4b7c 100644 --- a/third_party/harfbuzz-ng/harfbuzz.gyp +++ b/third_party/harfbuzz-ng/harfbuzz.gyp
@@ -30,6 +30,12 @@ }, { 'use_system_harfbuzz': 0, }], + ['OS=="linux" and target_arch=="arm" and chromeos==0', { + # Override use_system_harfbuzz for ARM cross compiling so system + # harfbuzz is not used because the corresponding package is not + # available. + 'use_system_harfbuzz': 0, + }], ], }, 'conditions': [
diff --git a/third_party/zlib/google/zip.h b/third_party/zlib/google/zip.h index 0232401..216b09e 100644 --- a/third_party/zlib/google/zip.h +++ b/third_party/zlib/google/zip.h
@@ -30,9 +30,10 @@ #if defined(OS_POSIX) // Zips files listed in |src_relative_paths| to destination specified by file -// descriptor |dest_fd|. The paths listed in |src_relative_paths| are relative -// to the |src_dir| and will be used as the file names in the created zip file. -// All source paths must be under |src_dir| in the file system hierarchy. +// descriptor |dest_fd|, without taking ownership of |dest_fd|. The paths listed +// in |src_relative_paths| are relative to the |src_dir| and will be used as the +// file names in the created zip file. All source paths must be under |src_dir| +// in the file system hierarchy. bool ZipFiles(const base::FilePath& src_dir, const std::vector<base::FilePath>& src_relative_paths, int dest_fd);
diff --git a/third_party/zlib/google/zip_internal.cc b/third_party/zlib/google/zip_internal.cc index d62e0bb..1f026c9 100644 --- a/third_party/zlib/google/zip_internal.cc +++ b/third_party/zlib/google/zip_internal.cc
@@ -79,6 +79,8 @@ #if defined(OS_POSIX) // Callback function for zlib that opens a file stream from a file descriptor. +// Since we do not own the file descriptor, dup it so that we can fdopen/fclose +// a file stream. void* FdOpenFileFunc(void* opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; @@ -90,18 +92,18 @@ else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; - if ((filename != NULL) && (mode_fopen != NULL)) - file = fdopen(*static_cast<int*>(opaque), mode_fopen); + if ((filename != NULL) && (mode_fopen != NULL)) { + int fd = dup(*static_cast<int*>(opaque)); + if (fd != -1) + file = fdopen(fd, mode_fopen); + } return file; } -// We don't actually close the file stream since that would close -// the underlying file descriptor, and we don't own it. However we do need to -// flush buffers and free |opaque| since we malloc'ed it in FillFdOpenFileFunc. -int CloseFileFunc(void* opaque, void* stream) { - fflush(static_cast<FILE*>(stream)); - free(opaque); +int FdCloseFileFunc(void* opaque, void* stream) { + fclose(static_cast<FILE*>(stream)); + free(opaque); // malloc'ed in FillFdOpenFileFunc() return 0; } @@ -110,7 +112,7 @@ void FillFdOpenFileFunc(zlib_filefunc_def* pzlib_filefunc_def, int fd) { fill_fopen_filefunc(pzlib_filefunc_def); pzlib_filefunc_def->zopen_file = FdOpenFileFunc; - pzlib_filefunc_def->zclose_file = CloseFileFunc; + pzlib_filefunc_def->zclose_file = FdCloseFileFunc; int* ptr_fd = static_cast<int*>(malloc(sizeof(fd))); *ptr_fd = fd; pzlib_filefunc_def->opaque = ptr_fd; @@ -119,6 +121,7 @@ #if defined(OS_WIN) // Callback function for zlib that opens a file stream from a Windows handle. +// Does not take ownership of the handle. void* HandleOpenFileFunc(void* opaque, const char* filename, int mode) { WIN32FILE_IOWIN file_ret; file_ret.hf = static_cast<HANDLE>(opaque); @@ -131,6 +134,11 @@ *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret; return ret; } + +int HandleCloseFileFunc(void* opaque, void* stream) { + free(stream); // malloc'ed in HandleOpenFileFunc() + return 0; +} #endif // A struct that contains data required for zlib functions to extract files from @@ -282,6 +290,7 @@ zlib_filefunc_def zip_funcs; fill_win32_filefunc(&zip_funcs); zip_funcs.zopen_file = HandleOpenFileFunc; + zip_funcs.zclose_file = HandleCloseFileFunc; zip_funcs.opaque = zip_handle; return unzOpen2("fd", &zip_funcs); }
diff --git a/third_party/zlib/google/zip_reader.h b/third_party/zlib/google/zip_reader.h index cda9cf7..9280f23 100644 --- a/third_party/zlib/google/zip_reader.h +++ b/third_party/zlib/google/zip_reader.h
@@ -102,8 +102,8 @@ // success. bool Open(const base::FilePath& zip_file_path); - // Opens the zip file referred to by the platform file |zip_fd|. - // Returns true on success. + // Opens the zip file referred to by the platform file |zip_fd|, without + // taking ownership of |zip_fd|. Returns true on success. bool OpenFromPlatformFile(base::PlatformFile zip_fd); // Opens the zip data stored in |data|. This class uses a weak reference to
diff --git a/third_party/zlib/google/zip_reader_unittest.cc b/third_party/zlib/google/zip_reader_unittest.cc index 09fc241..d4bb579 100644 --- a/third_party/zlib/google/zip_reader_unittest.cc +++ b/third_party/zlib/google/zip_reader_unittest.cc
@@ -573,4 +573,13 @@ reader.Close(); } +// This test exposes http://crbug.com/430959, at least on OS X +TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) { + for (int i = 0; i < 100000; ++i) { + FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY); + ZipReader reader; + ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file())); + } +} + } // namespace zip
diff --git a/tools/android/checkstyle/checkstyle.py b/tools/android/checkstyle/checkstyle.py index c8ad04f..0c260bb 100644 --- a/tools/android/checkstyle/checkstyle.py +++ b/tools/android/checkstyle/checkstyle.py
@@ -13,7 +13,7 @@ os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)) CHECKSTYLE_ROOT = os.path.join(CHROMIUM_SRC, 'third_party', 'checkstyle', - 'checkstyle-5.9-all.jar') + 'checkstyle-6.1-all.jar') def RunCheckstyle(input_api, output_api, style_file):
diff --git a/tools/android/checkstyle/chromium-style-5.0.xml b/tools/android/checkstyle/chromium-style-5.0.xml index 46b19e9..c43f779 100644 --- a/tools/android/checkstyle/chromium-style-5.0.xml +++ b/tools/android/checkstyle/chromium-style-5.0.xml
@@ -91,7 +91,7 @@ </module> <module name="LineLength"> <property name="severity" value="error"/> - <property name="ignorePattern" value="^import.*$" /> + <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/> <property name="max" value="100"/> </module> <module name="LeftCurly"> @@ -138,6 +138,17 @@ <property name="allowLineBreaks" value="true"/> <property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/> </module> + <module name="GenericWhitespace"> + <property name="severity" value="error"/> + <message key="ws.followed" + value="GenericWhitespace ''{0}'' is followed by whitespace."/> + <message key="ws.preceded" + value="GenericWhitespace ''{0}'' is preceded with whitespace."/> + <message key="ws.illegalFollow" + value="GenericWhitespace ''{0}'' should followed by whitespace."/> + <message key="ws.notPreceded" + value="GenericWhitespace ''{0}'' is not preceded with whitespace."/> + </module> <module name="EmptyStatement"> <property name="severity" value="error"/> </module> @@ -166,22 +177,22 @@ </module> <!-- TODO(aurimas): make OperatorWrap into an error once all the warnings are fixed. --> <module name="OperatorWrap"> - <property name="severity" value="warning"/> + <property name="severity" value="error"/> <property name="option" value="NL" /> <property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR " /> </module> <module name="OperatorWrap"> - <property name="severity" value="warning"/> + <property name="severity" value="error"/> <property name="option" value="eol"/> <property name="tokens" value="ASSIGN"/> </module> <module name="SeparatorWrap"> - <property name="severity" value="warning"/> + <property name="severity" value="error"/> <property name="tokens" value="DOT"/> <property name="option" value="nl"/> </module> <module name="SeparatorWrap"> - <property name="severity" value="warning"/> + <property name="severity" value="error"/> <property name="tokens" value="COMMA"/> <property name="option" value="EOL"/> </module>
diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp index c8bc543..7e36653 100644 --- a/tools/clang/plugins/ChromeClassTester.cpp +++ b/tools/clang/plugins/ChromeClassTester.cpp
@@ -206,7 +206,7 @@ // Enum type with _LAST members where _LAST doesn't mean last enum value. ignored_record_names_.insert("ServerFieldType"); - // Used heavily in ui_unittests and once in views_unittests. Fixing this + // Used heavily in ui_base_unittests and once in views_unittests. Fixing this // isn't worth the overhead of an additional library. ignored_record_names_.insert("TestAnimationDelegate");
diff --git a/tools/clang/plugins/FindBadConstructsConsumer.cpp b/tools/clang/plugins/FindBadConstructsConsumer.cpp index 0a230e0..f08ca71 100644 --- a/tools/clang/plugins/FindBadConstructsConsumer.cpp +++ b/tools/clang/plugins/FindBadConstructsConsumer.cpp
@@ -724,28 +724,37 @@ the_end(record->field_end()); SourceLocation weak_ptr_factory_location; // Invalid initially. for (; iter != the_end; ++iter) { - // If we enter the loop but have already seen a matching WeakPtrFactory, - // it means there is at least one member after the factory. - if (weak_ptr_factory_location.isValid()) { - diagnostic().Report(weak_ptr_factory_location, - diag_weak_ptr_factory_order_); - } const TemplateSpecializationType* template_spec_type = iter->getType().getTypePtr()->getAs<TemplateSpecializationType>(); + bool param_is_weak_ptr_factory_to_self = false; if (template_spec_type) { const TemplateDecl* template_decl = template_spec_type->getTemplateName().getAsTemplateDecl(); - if (template_decl && template_spec_type->getNumArgs() >= 1) { + if (template_decl && template_spec_type->getNumArgs() == 1) { if (template_decl->getNameAsString().compare("WeakPtrFactory") == 0 && GetNamespace(template_decl) == "base") { + // Only consider WeakPtrFactory members which are specialized for the + // owning class. const TemplateArgument& arg = template_spec_type->getArg(0); if (arg.getAsType().getTypePtr()->getAsCXXRecordDecl() == record->getTypeForDecl()->getAsCXXRecordDecl()) { - weak_ptr_factory_location = iter->getLocation(); + if (!weak_ptr_factory_location.isValid()) { + // Save the first matching WeakPtrFactory member for the + // diagnostic. + weak_ptr_factory_location = iter->getLocation(); + } + param_is_weak_ptr_factory_to_self = true; } } } } + // If we've already seen a WeakPtrFactory<OwningType> and this param is not + // one of those, it means there is at least one member after a factory. + if (weak_ptr_factory_location.isValid() && + !param_is_weak_ptr_factory_to_self) { + diagnostic().Report(weak_ptr_factory_location, + diag_weak_ptr_factory_order_); + } } }
diff --git a/tools/clang/plugins/tests/weak_ptr_factory.cpp b/tools/clang/plugins/tests/weak_ptr_factory.cpp index 79c23b4..50de97c 100644 --- a/tools/clang/plugins/tests/weak_ptr_factory.cpp +++ b/tools/clang/plugins/tests/weak_ptr_factory.cpp
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "weak_ptr_factory.h" + namespace should_succeed { class OnlyMember { @@ -27,6 +28,13 @@ base::WeakPtrFactory<FirstFactoryRefersToOtherType> factory_; }; +class TwoFactories { + bool bool_member_; + int int_member_; + base::WeakPtrFactory<TwoFactories> factory1_; + base::WeakPtrFactory<TwoFactories> factory2_; +}; + } // namespace should_succeed namespace should_fail { @@ -42,6 +50,13 @@ int int_member_; }; +class TwoFactoriesOneBad { + bool bool_member_; + base::WeakPtrFactory<TwoFactoriesOneBad> factory1_; + int int_member_; + base::WeakPtrFactory<TwoFactoriesOneBad> factory2_; +}; + } // namespace should_fail int main() {
diff --git a/tools/clang/plugins/tests/weak_ptr_factory.txt b/tools/clang/plugins/tests/weak_ptr_factory.txt index f9c2c0a..820b7db 100644 --- a/tools/clang/plugins/tests/weak_ptr_factory.txt +++ b/tools/clang/plugins/tests/weak_ptr_factory.txt
@@ -1,7 +1,10 @@ -weak_ptr_factory.cpp:35:38: warning: [chromium-style] WeakPtrFactory members which refer to their outer class must be the last member in the outer class definition. +weak_ptr_factory.cpp:43:38: warning: [chromium-style] WeakPtrFactory members which refer to their outer class must be the last member in the outer class definition. base::WeakPtrFactory<FactoryFirst> factory_; ^ -weak_ptr_factory.cpp:41:39: warning: [chromium-style] WeakPtrFactory members which refer to their outer class must be the last member in the outer class definition. +weak_ptr_factory.cpp:49:39: warning: [chromium-style] WeakPtrFactory members which refer to their outer class must be the last member in the outer class definition. base::WeakPtrFactory<FactoryMiddle> factory_; ^ -2 warnings generated. +weak_ptr_factory.cpp:55:44: warning: [chromium-style] WeakPtrFactory members which refer to their outer class must be the last member in the outer class definition. + base::WeakPtrFactory<TwoFactoriesOneBad> factory1_; + ^ +3 warnings generated.
diff --git a/tools/clang/rewrite_scoped_refptr/CMakeLists.txt b/tools/clang/rewrite_scoped_refptr/CMakeLists.txt index 9b0184d..aa47400 100644 --- a/tools/clang/rewrite_scoped_refptr/CMakeLists.txt +++ b/tools/clang/rewrite_scoped_refptr/CMakeLists.txt
@@ -2,6 +2,7 @@ BitReader MCParser Option + X86AsmParser ) add_llvm_executable(rewrite_scoped_refptr
diff --git a/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp b/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp index fe9d860..e11d5f9 100644 --- a/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp +++ b/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
@@ -22,6 +22,7 @@ #include "clang/Tooling/Refactoring.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" +#include "llvm/support/TargetSelect.h" using namespace clang::ast_matchers; using clang::tooling::CommonOptionsParser; @@ -255,6 +256,10 @@ static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); int main(int argc, const char* argv[]) { + // TODO(dcheng): Clang tooling should do this itself. + // http://llvm.org/bugs/show_bug.cgi?id=21627 + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmParser(); llvm::cl::OptionCategory category("Remove scoped_refptr conversions"); CommonOptionsParser options(argc, argv, category); clang::tooling::ClangTool tool(options.getCompilations(),
diff --git a/tools/clang/scripts/generate_win_compdb.py b/tools/clang/scripts/generate_win_compdb.py new file mode 100755 index 0000000..32f5f75 --- /dev/null +++ b/tools/clang/scripts/generate_win_compdb.py
@@ -0,0 +1,83 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Clang tools on Windows are still a bit busted. The tooling can't handle +backslashes in paths, doesn't understand how to read .rsp files, etc. In +addition, ninja generates compile commands prefixed with the ninja msvc helper, +which also confuses clang. This script generates a compile DB that should mostly +work until clang tooling can be improved upstream. +""" + +import os +import re +import json +import shlex +import subprocess +import sys + + +_NINJA_MSVC_WRAPPER = re.compile('ninja -t msvc -e .+? -- ') +_RSP_RE = re.compile(r' (@(.+?\.rsp)) ') + + +def _ProcessEntry(e): + # Strip off the ninja -t msvc wrapper. + e['command'] = _NINJA_MSVC_WRAPPER.sub('', e['command']) + + # Prepend --driver-mode=cl to the command's arguments. + # Escape backslashes so shlex doesn't try to interpret them. + escaped_command = e['command'].replace('\\', '\\\\') + split_command = shlex.split(escaped_command) + e['command'] = ' '.join( + split_command[:1] + ['--driver-mode=cl'] + split_command[1:]) + + # Expand the contents of the response file, if any. + # http://llvm.org/bugs/show_bug.cgi?id=21634 + try: + match = _RSP_RE.search(e['command']) + rsp_path = os.path.join(e['directory'], match.group(2)) + rsp_contents = file(rsp_path).read() + e['command'] = ''.join([ + e['command'][:match.start(1)], + rsp_contents, + e['command'][match.end(1):]]) + except IOError: + pass + + # TODO(dcheng): This should be implemented in Clang tooling. + # http://llvm.org/bugs/show_bug.cgi?id=19687 + # Finally, use slashes instead of backslashes to avoid bad escaping by the + # tooling. This should really only matter for command, but we do it for all + # keys for consistency. + e['directory'] = e['directory'].replace('\\', '/') + e['command'] = e['command'].replace('\\', '/') + e['file'] = e['file'].replace('\\', '/') + + return e + + +def main(argv): + # First, generate the compile database. + print 'Generating compile DB with ninja...' + compile_db_as_json = subprocess.check_output(shlex.split( + 'ninja -C out/Debug -t compdb cc cxx objc objcxx')) + + compile_db = json.loads(compile_db_as_json) + print 'Read in %d entries from the compile db' % len(compile_db) + compile_db = [_ProcessEntry(e) for e in compile_db] + original_length = len(compile_db) + + # Filter out NaCl stuff. The clang tooling chokes on them. + compile_db = [e for e in compile_db if '_nacl.cc.pdb' not in e['command'] + and '_nacl_win64.cc.pdb' not in e['command']] + print 'Filtered out %d entries...' % (original_length - len(compile_db)) + f = file('out/Debug/compile_commands.json', 'w') + f.write(json.dumps(compile_db, indent=2)) + print 'Done!' + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:]))
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py index 61417e4..3725ca3 100755 --- a/tools/clang/scripts/run_tool.py +++ b/tools/clang/scripts/run_tool.py
@@ -9,6 +9,9 @@ If you want to run the tool across all Chromium code: run_tool.py <tool> <path/to/compiledb> +If you want to include all files mentioned in the compilation database: +run_tool.py <tool> <path/to/compiledb> --all + If you only want to run the tool across just chrome/browser and content/browser: run_tool.py <tool> <path/to/compiledb> chrome/browser content/browser @@ -37,6 +40,7 @@ import collections import functools +import json import multiprocessing import os.path import pipes @@ -67,6 +71,20 @@ return [os.path.realpath(p) for p in output.splitlines()] +def _GetFilesFromCompileDB(build_directory): + """ Gets the list of files mentioned in the compilation database. + + Args: + build_directory: Directory that contains the compile database. + """ + compiledb_path = os.path.join(build_directory, 'compile_commands.json') + with open(compiledb_path, 'rb') as compiledb_file: + json_commands = json.load(compiledb_file) + + return [os.path.join(entry['directory'], entry['file']) + for entry in json_commands] + + def _ExtractEditsFromStdout(build_directory, stdout): """Extracts generated list of edits from the tool's stdout. @@ -295,7 +313,10 @@ if not os.path.isfile(clang_format_diff_path) or sys.platform == 'win32': clang_format_diff_path = None - filenames = frozenset(_GetFilesFromGit(argv[2:])) + if len(argv) == 3 and argv[2] == '--all': + filenames = frozenset(_GetFilesFromCompileDB(argv[1])) + else: + filenames = frozenset(_GetFilesFromGit(argv[2:])) # Filter out files that aren't C/C++/Obj-C/Obj-C++. extensions = frozenset(('.c', '.cc', '.m', '.mm')) dispatcher = _CompilerDispatcher(argv[0], argv[1],
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh index e576cac..ad534ad 100755 --- a/tools/clang/scripts/update.sh +++ b/tools/clang/scripts/update.sh
@@ -704,7 +704,8 @@ --platform=android-14 \ --install-dir="${LLVM_BUILD_DIR}/android-toolchain" \ --system=linux-x86_64 \ - --stl=stlport + --stl=stlport \ + --toolchain=arm-linux-androideabi-4.9 # Android NDK r9d copies a broken unwind.h into the toolchain, see # http://crbug.com/357890
diff --git a/tools/clang/translation_unit/CMakeLists.txt b/tools/clang/translation_unit/CMakeLists.txt new file mode 100644 index 0000000..9b4fd8b --- /dev/null +++ b/tools/clang/translation_unit/CMakeLists.txt
@@ -0,0 +1,26 @@ +set(LLVM_LINK_COMPONENTS + BitReader + MCParser + Option + ) + +add_llvm_executable(translation_unit + TranslationUnitGenerator.cpp + ) + +target_link_libraries(translation_unit + clangAST + clangASTMatchers + clangAnalysis + clangBasic + clangDriver + clangEdit + clangFrontend + clangLex + clangParse + clangSema + clangSerialization + clangTooling + ) + +cr_install(TARGETS translation_unit RUNTIME DESTINATION bin)
diff --git a/tools/clang/translation_unit/TranslationUnitGenerator.cpp b/tools/clang/translation_unit/TranslationUnitGenerator.cpp new file mode 100644 index 0000000..df9eaeb --- /dev/null +++ b/tools/clang/translation_unit/TranslationUnitGenerator.cpp
@@ -0,0 +1,218 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This implements a Clang tool to generate compilation information that is +// sufficient to recompile the code with clang. For each compilation unit, all +// source files which are necessary for compiling it are determined. For each +// compilation unit, a file is created containing a list of all file paths of +// included files. + +#include <assert.h> +#include <unistd.h> +#include <fstream> +#include <iostream> +#include <memory> +#include <set> +#include <stack> +#include <string> +#include <vector> + +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/Support/CommandLine.h" + +using clang::tooling::CommonOptionsParser; +using std::set; +using std::stack; +using std::string; +using std::vector; + +namespace { +// Set of preprocessor callbacks used to record files included. +class IncludeFinderPPCallbacks : public clang::PPCallbacks { + public: + IncludeFinderPPCallbacks(clang::SourceManager* source_manager, + string* main_source_file, + set<string>* source_file_paths) + : source_manager_(source_manager), + main_source_file_(main_source_file), + source_file_paths_(source_file_paths) {} + void FileChanged(clang::SourceLocation /*loc*/, + clang::PPCallbacks::FileChangeReason reason, + clang::SrcMgr::CharacteristicKind /*file_type*/, + clang::FileID /*prev_fid*/) override; + void AddFile(const string& path); + void InclusionDirective(clang::SourceLocation hash_loc, + const clang::Token& include_tok, + llvm::StringRef file_name, + bool is_angled, + clang::CharSourceRange range, + const clang::FileEntry* file, + llvm::StringRef search_path, + llvm::StringRef relative_path, + const clang::Module* imported) override; + void EndOfMainFile() override; + + private: + clang::SourceManager* const source_manager_; + string* const main_source_file_; + set<string>* const source_file_paths_; + // The path of the file that was last referenced by an inclusion directive, + // normalized for includes that are relative to a different source file. + string last_inclusion_directive_; + // The stack of currently parsed files. top() gives the current file. + stack<string> current_files_; +}; + +void IncludeFinderPPCallbacks::FileChanged( + clang::SourceLocation /*loc*/, + clang::PPCallbacks::FileChangeReason reason, + clang::SrcMgr::CharacteristicKind /*file_type*/, + clang::FileID /*prev_fid*/) { + if (reason == clang::PPCallbacks::EnterFile) { + if (!last_inclusion_directive_.empty()) { + current_files_.push(last_inclusion_directive_); + } else { + current_files_.push( + source_manager_->getFileEntryForID(source_manager_->getMainFileID()) + ->getName()); + } + } else if (reason == ExitFile) { + current_files_.pop(); + } + // Other reasons are not interesting for us. +} + +void IncludeFinderPPCallbacks::AddFile(const string& path) { + source_file_paths_->insert(path); +} + +void IncludeFinderPPCallbacks::InclusionDirective( + clang::SourceLocation hash_loc, + const clang::Token& include_tok, + llvm::StringRef file_name, + bool is_angled, + clang::CharSourceRange range, + const clang::FileEntry* file, + llvm::StringRef search_path, + llvm::StringRef relative_path, + const clang::Module* imported) { + if (!file) + return; + + assert(!current_files_.top().empty()); + const clang::DirectoryEntry* const search_path_entry = + source_manager_->getFileManager().getDirectory(search_path); + const clang::DirectoryEntry* const current_file_parent_entry = + source_manager_->getFileManager() + .getFile(current_files_.top().c_str()) + ->getDir(); + + // If the include file was found relatively to the current file's parent + // directory or a search path, we need to normalize it. This is necessary + // because llvm internalizes the path by which an inode was first accessed, + // and always returns that path afterwards. If we do not normalize this + // we will get an error when we replay the compilation, as the virtual + // file system is not aware of inodes. + if (search_path_entry == current_file_parent_entry) { + string parent = + llvm::sys::path::parent_path(current_files_.top().c_str()).str(); + + // If the file is a top level file ("file.cc"), we normalize to a path + // relative to "./". + if (parent.empty() || parent == "/") + parent = "."; + + // Otherwise we take the literal path as we stored it for the current + // file, and append the relative path. + last_inclusion_directive_ = parent + "/" + relative_path.str(); + } else if (!search_path.empty()) { + last_inclusion_directive_ = string(search_path) + "/" + relative_path.str(); + } else { + last_inclusion_directive_ = file_name.str(); + } + AddFile(last_inclusion_directive_); +} + +void IncludeFinderPPCallbacks::EndOfMainFile() { + const clang::FileEntry* main_file = + source_manager_->getFileEntryForID(source_manager_->getMainFileID()); + assert(*main_source_file_ == main_file->getName()); + AddFile(main_file->getName()); +} + +class CompilationIndexerAction : public clang::PreprocessorFrontendAction { + public: + CompilationIndexerAction() {} + void ExecuteAction() override; + + // Runs the preprocessor over the translation unit. + // This triggers the PPCallbacks we register to intercept all required + // files for the compilation. + void Preprocess(); + void EndSourceFileAction() override; + + private: + // Set up the state extracted during the compilation, and run Clang over the + // input. + string main_source_file_; + // Maps file names to their contents as read by Clang's source manager. + set<string> source_file_paths_; +}; + +void CompilationIndexerAction::ExecuteAction() { + vector<clang::FrontendInputFile> inputs = + getCompilerInstance().getFrontendOpts().Inputs; + assert(inputs.size() == 1); + main_source_file_ = inputs[0].getFile(); + + Preprocess(); +} + +void CompilationIndexerAction::Preprocess() { + clang::Preprocessor& preprocessor = getCompilerInstance().getPreprocessor(); + preprocessor.addPPCallbacks(llvm::make_unique<IncludeFinderPPCallbacks>( + &getCompilerInstance().getSourceManager(), + &main_source_file_, + &source_file_paths_)); + preprocessor.IgnorePragmas(); + preprocessor.SetSuppressIncludeNotFoundError(true); + preprocessor.EnterMainSourceFile(); + clang::Token token; + do { + preprocessor.Lex(token); + } while (token.isNot(clang::tok::eof)); +} + +void CompilationIndexerAction::EndSourceFileAction() { + std::ofstream out(main_source_file_ + ".filepaths"); + for (string path : source_file_paths_) { + out << path << std::endl; + } +} +} // namespace + +static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); + +int main(int argc, const char* argv[]) { + llvm::cl::OptionCategory category("TranslationUnitGenerator Tool"); + CommonOptionsParser options(argc, argv, category); + std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory = + clang::tooling::newFrontendActionFactory<CompilationIndexerAction>(); + clang::tooling::ClangTool tool(options.getCompilations(), + options.getSourcePathList()); + // This clang tool does not actually produce edits, but run_tool.py expects + // this. So we just print an empty edit block. + llvm::outs() << "==== BEGIN EDITS ====\n"; + llvm::outs() << "==== END EDITS ====\n"; + return tool.run(frontend_factory.get()); +}
diff --git a/tools/clang/translation_unit/test_files/binomial.h b/tools/clang/translation_unit/test_files/binomial.h new file mode 100644 index 0000000..c67b273 --- /dev/null +++ b/tools/clang/translation_unit/test_files/binomial.h
@@ -0,0 +1,12 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#ifndef TOOLS_CLANG_TRANSLATION_UNIT_TEST_FILES_BINOMIAL_H_ +#define TOOLS_CLANG_TRANSLATION_UNIT_TEST_FILES_BINOMIAL_H_ + +int binomial(int n, int k) { + return k > 0 ? binomial(n - 1, k - 1) * n / k : 1; +} + +#endif // TOOLS_CLANG_TRANSLATION_UNIT_TEST_FILES_BINOMIAL_H_
diff --git a/tools/clang/translation_unit/test_files/test.cc b/tools/clang/translation_unit/test_files/test.cc new file mode 100644 index 0000000..e735f55 --- /dev/null +++ b/tools/clang/translation_unit/test_files/test.cc
@@ -0,0 +1,16 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "test.h" + +#include "binomial.h" + +// Notice that "binomial.h" is included both here and in the "test.h" file. +// The tool should however print the path to this header file only once. + +int main() { + // Just some nonesense calculations. + int result = calculateNumberOfWaysToDistributeNItemsAmongKPersons(10, 5); + return result + binomial(42, 1); +}
diff --git a/tools/clang/translation_unit/test_files/test.cc.filepaths.expected b/tools/clang/translation_unit/test_files/test.cc.filepaths.expected new file mode 100644 index 0000000..3dc4421 --- /dev/null +++ b/tools/clang/translation_unit/test_files/test.cc.filepaths.expected
@@ -0,0 +1,3 @@ +./binomial.h +./test.cc +./test.h
diff --git a/tools/clang/translation_unit/test_files/test.h b/tools/clang/translation_unit/test_files/test.h new file mode 100644 index 0000000..8cc20ce --- /dev/null +++ b/tools/clang/translation_unit/test_files/test.h
@@ -0,0 +1,16 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TOOLS_CLANG_TRANSLATION_UNIT_TEST_FILES_TEST_H_ +#define TOOLS_CLANG_TRANSLATION_UNIT_TEST_FILES_TEST_H_ + +#include "binomial.h" + +// Number of ways to distribute n items of the same thing to k persons; each +// person should get at least one item. +int calculateNumberOfWaysToDistributeNItemsAmongKPersons(int n, int k) { + return binomial(n - 1, k - 1); +} + +#endif // TOOLS_CLANG_TRANSLATION_UNIT_TEST_FILES_TEST_H_
diff --git a/tools/clang/translation_unit/test_translation_unit.py b/tools/clang/translation_unit/test_translation_unit.py new file mode 100755 index 0000000..eb5cce8 --- /dev/null +++ b/tools/clang/translation_unit/test_translation_unit.py
@@ -0,0 +1,101 @@ +#!/usr/bin/env python +# Copyright (c) 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Test for TranslationUnitGenerator tool.""" + +import difflib +import glob +import json +import ntpath +import os +import os.path +import subprocess +import sys + + +def _GenerateCompileCommands(files): + """Returns a JSON string containing a compilation database for the input.""" + return json.dumps([{'directory': '.', + 'command': 'clang++ -fsyntax-only -std=c++11 -c %s' % f, + 'file': f} for f in files], indent=2) + + +def _NumberOfTestsToString(tests): + """Returns an English sentence describing the number of tests.""" + return "%d test%s" % (tests, 's' if tests != 1 else '') + + +# Before running this test script, please build the translation_unit clang tool +# first. This is explained here: +# https://code.google.com/p/chromium/wiki/ClangToolRefactoring +def main(): + tools_clang_directory = os.path.dirname(os.path.dirname( + os.path.realpath(__file__))) + tools_clang_scripts_directory = os.path.join(tools_clang_directory, 'scripts') + test_directory_for_tool = os.path.join( + tools_clang_directory, 'translation_unit', 'test_files') + compile_database = os.path.join(test_directory_for_tool, + 'compile_commands.json') + source_files = glob.glob(os.path.join(test_directory_for_tool, '*.cc')) + + # Generate a temporary compilation database to run the tool over. + with open(compile_database, 'w') as f: + f.write(_GenerateCompileCommands(source_files)) + + args = ['python', + os.path.join(tools_clang_scripts_directory, 'run_tool.py'), + 'translation_unit', + test_directory_for_tool] + args.extend(source_files) + run_tool = subprocess.Popen(args, stdout=subprocess.PIPE) + stdout, _ = run_tool.communicate() + if run_tool.returncode != 0: + print 'run_tool failed:\n%s' % stdout + sys.exit(1) + + passed = 0 + failed = 0 + for actual in source_files: + actual += '.filepaths' + expected = actual + '.expected' + print '[ RUN ] %s' % os.path.relpath(actual) + expected_output = actual_output = None + with open(expected, 'r') as f: + expected_output = f.readlines() + with open(actual, 'r') as f: + actual_output = f.readlines() + has_same_filepaths = True + for expected_line, actual_line in zip(expected_output, actual_output): + if ntpath.basename(expected_line) != ntpath.basename(actual_line): + sys.stdout.write(ntpath.basename(expected_line)) + sys.stdout.write(ntpath.basename(actual_line)) + has_same_filepaths = False + break + if not has_same_filepaths: + failed += 1 + for line in difflib.unified_diff(expected_output, actual_output, + fromfile=os.path.relpath(expected), + tofile=os.path.relpath(actual)): + sys.stdout.write(line) + print '[ FAILED ] %s' % os.path.relpath(actual) + # Don't clean up the file on failure, so the results can be referenced + # more easily. + continue + print '[ OK ] %s' % os.path.relpath(actual) + passed += 1 + os.remove(actual) + + if failed == 0: + os.remove(compile_database) + + print '[==========] %s ran.' % _NumberOfTestsToString(len(source_files)) + if passed > 0: + print '[ PASSED ] %s.' % _NumberOfTestsToString(passed) + if failed > 0: + print '[ FAILED ] %s.' % _NumberOfTestsToString(failed) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py index 8f5432f..677cb63 100755 --- a/tools/valgrind/chrome_tests.py +++ b/tools/valgrind/chrome_tests.py
@@ -470,6 +470,9 @@ def TestUIBaseUnit(self): return self.SimpleTest("chrome", "ui_base_unittests") + def TestUIChromeOS(self): + return self.SimpleTest("chrome", "ui_chromeos_unittests") + def TestURL(self): return self.SimpleTest("chrome", "url_unittests") @@ -712,6 +715,7 @@ "sync_integration_tests": TestSyncIntegration, "sync_integration": TestSyncIntegration, "ui_base_unit": TestUIBaseUnit, "ui_base_unittests": TestUIBaseUnit, + "ui_chromeos": TestUIChromeOS, "ui_chromeos_unittests": TestUIChromeOS, "unit": TestUnit, "unit_tests": TestUnit, "url": TestURL, "url_unittests": TestURL, "views": TestViews, "views_unittests": TestViews,
diff --git a/tools/valgrind/gtest_exclude/base_unittests.gtest.txt b/tools/valgrind/gtest_exclude/base_unittests.gtest.txt index aa85c27..74a4ac5 100644 --- a/tools/valgrind/gtest_exclude/base_unittests.gtest.txt +++ b/tools/valgrind/gtest_exclude/base_unittests.gtest.txt
@@ -27,3 +27,6 @@ # Crashes under Valgrind, see http://crbug.com/355436 OutOfMemoryHandledTest.Unchecked* + +# Fail under Valgrind, see http://crbug.com/431702 +ProcMapsTest.ReadProcMaps
diff --git a/tools/valgrind/gtest_exclude/components_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/components_unittests.gtest-drmemory_win32.txt new file mode 100644 index 0000000..a8edd28 --- /dev/null +++ b/tools/valgrind/gtest_exclude/components_unittests.gtest-drmemory_win32.txt
@@ -0,0 +1,3 @@ +# http://crbug.com/435320 +MetricsServiceTest.InitialStabilityLogAfterCrash +MetricsServiceTest.InitialStabilityLogAtProviderRequest
diff --git a/tools/valgrind/gtest_exclude/content_unittests.gtest.txt b/tools/valgrind/gtest_exclude/content_unittests.gtest.txt index 3376b22..03eb062 100644 --- a/tools/valgrind/gtest_exclude/content_unittests.gtest.txt +++ b/tools/valgrind/gtest_exclude/content_unittests.gtest.txt
@@ -10,3 +10,6 @@ # http://crbug.com/430391 WebDataConsumerHandleImplTest.* + +# http://crbug.com/435441 +PluginLoaderPosixTest.*
diff --git a/ui/base/x/x11_foreign_window_manager.h b/ui/base/x/x11_foreign_window_manager.h index 2bf1937..354cfba 100644 --- a/ui/base/x/x11_foreign_window_manager.h +++ b/ui/base/x/x11_foreign_window_manager.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/compiler_specific.h" #include "ui/base/ui_base_export.h" #include "ui/gfx/x/x11_types.h"
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 6bcb02a..e0b125a 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -114,7 +114,7 @@ CommandLine* command_line = CommandLine::ForCurrentProcess(); cc::LayerTreeSettings settings; - settings.refresh_rate = + settings.renderer_settings.refresh_rate = context_factory_->DoesCreateTestContexts() ? kTestRefreshRate : kDefaultRefreshRate; @@ -122,7 +122,7 @@ settings.throttle_frame_production = !command_line->HasSwitch(switches::kDisableGpuVsync); #if !defined(OS_MACOSX) - settings.partial_swap_enabled = + settings.renderer_settings.partial_swap_enabled = !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); #endif #if defined(OS_CHROMEOS) @@ -253,10 +253,9 @@ if (!IsLocked()) { // TODO(nduca): Temporary while compositor calls // compositeImmediately() directly. - cc::BeginFrameArgs args = - cc::BeginFrameArgs::Create(gfx::FrameTime::Now(), - base::TimeTicks(), - cc::BeginFrameArgs::DefaultInterval()); + cc::BeginFrameArgs args = cc::BeginFrameArgs::Create( + gfx::FrameTime::Now(), base::TimeTicks(), + cc::BeginFrameArgs::DefaultInterval(), cc::BeginFrameArgs::SYNCHRONOUS); BeginMainFrame(args); host_->Composite(args.frame_time); }
diff --git a/ui/compositor/layer_tree_owner.h b/ui/compositor/layer_tree_owner.h index 8b75355..0b2c478 100644 --- a/ui/compositor/layer_tree_owner.h +++ b/ui/compositor/layer_tree_owner.h
@@ -6,6 +6,7 @@ #define UI_COMPOSITOR_LAYER_TREE_OWNER_H_ #include "base/basictypes.h" +#include "base/compiler_specific.h" #include "ui/compositor/compositor_export.h" namespace ui {
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py index da668ec..6fff4cb 100755 --- a/ui/gl/generate_bindings.py +++ b/ui/gl/generate_bindings.py
@@ -39,18 +39,32 @@ 'names': ['glAttachShader'], 'arguments': 'GLuint program, GLuint shader', }, { 'return_type': 'void', - 'names': ['glBeginQuery'], + 'versions': [{ 'name': 'glBeginQuery', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], 'arguments': 'GLenum target, GLuint id', }, { 'return_type': 'void', 'names': ['glBeginQueryARB', 'glBeginQueryEXT'], 'arguments': 'GLenum target, GLuint id', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glBeginTransformFeedback', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum primitiveMode', }, +{ 'return_type': 'void', 'names': ['glBindAttribLocation'], 'arguments': 'GLuint program, GLuint index, const char* name', }, { 'return_type': 'void', 'names': ['glBindBuffer'], 'arguments': 'GLenum target, GLuint buffer', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glBindBufferBase', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum target, GLuint index, GLuint buffer', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glBindBufferRange', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum target, GLuint index, GLuint buffer, GLintptr offset, ' + 'GLsizeiptr size', }, +{ 'return_type': 'void', 'names': ['glBindFragDataLocation'], 'arguments': 'GLuint program, GLuint colorNumber, const char* name', }, { 'return_type': 'void', @@ -64,9 +78,17 @@ 'names': ['glBindRenderbufferEXT', 'glBindRenderbuffer'], 'arguments': 'GLenum target, GLuint renderbuffer', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glBindSampler', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLuint unit, GLuint sampler', }, +{ 'return_type': 'void', 'names': ['glBindTexture'], 'arguments': 'GLenum target, GLuint texture', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glBindTransformFeedback', + 'gl_versions': ['gl4', 'es3'] }], + 'arguments': 'GLenum target, GLuint id', }, +{ 'return_type': 'void', 'known_as': 'glBindVertexArrayOES', 'versions': [{ 'name': 'glBindVertexArray', 'gl_versions': ['gl3', 'gl4', 'es3'] }, @@ -133,6 +155,23 @@ 'names': ['glClear'], 'arguments': 'GLbitfield mask', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glClearBufferfi', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum buffer, GLint drawbuffer, const GLfloat depth, ' + 'GLint stencil', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glClearBufferfv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum buffer, GLint drawbuffer, const GLfloat* value', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glClearBufferiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum buffer, GLint drawbuffer, const GLint* value', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glClearBufferuiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum buffer, GLint drawbuffer, const GLuint* value', }, +{ 'return_type': 'void', 'names': ['glClearColor'], 'arguments': 'GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha', }, { 'return_type': 'void', @@ -160,11 +199,32 @@ 'GLenum target, GLint level, GLenum internalformat, GLsizei width, ' 'GLsizei height, GLint border, GLsizei imageSize, const void* data', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glCompressedTexImage3D', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': + 'GLenum target, GLint level, GLenum internalformat, GLsizei width, ' + 'GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, ' + 'const void* data', }, +{ 'return_type': 'void', 'names': ['glCompressedTexSubImage2D'], 'arguments': - 'GLenum target, GLint level, GLint xoffset, GLint yoffset, ' - 'GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, ' - 'const void* data', }, + 'GLenum target, GLint level, GLint xoffset, GLint yoffset, ' + 'GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, ' + 'const void* data', }, +# TODO(zmo): wait for MOCK_METHOD11. +# { 'return_type': 'void', +# 'versions': [{ 'name': 'glCompressedTexSubImage3D', +# 'gl_versions': ['gl3', 'gl4', 'es3'] }], +# 'arguments': +# 'GLenum target, GLint level, GLint xoffset, GLint yoffset, ' +# 'GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, ' +# 'GLenum format, GLsizei imageSize, const void* data', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glCopyBufferSubData', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.1 or higher. + 'arguments': + 'GLenum readTarget, GLenum writeTarget, GLintptr readOffset, ' + 'GLintptr writeOffset, GLsizeiptr size', }, { 'return_type': 'void', 'names': ['glCopyTexImage2D'], 'arguments': @@ -175,6 +235,12 @@ 'arguments': 'GLenum target, GLint level, GLint xoffset, ' 'GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glCopyTexSubImage3D', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': + 'GLenum target, GLint level, GLint xoffset, GLint yoffset, ' + 'GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height', }, { 'return_type': 'GLuint', 'names': ['glCreateProgram'], 'arguments': 'void', }, @@ -202,7 +268,8 @@ 'names': ['glDeleteProgram'], 'arguments': 'GLuint program', }, { 'return_type': 'void', - 'names': ['glDeleteQueries'], + 'versions': [{ 'name': 'glDeleteQueries', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], 'arguments': 'GLsizei n, const GLuint* ids', }, { 'return_type': 'void', 'names': ['glDeleteQueriesARB', 'glDeleteQueriesEXT'], @@ -211,6 +278,10 @@ 'names': ['glDeleteRenderbuffersEXT', 'glDeleteRenderbuffers'], 'arguments': 'GLsizei n, const GLuint* renderbuffers', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glDeleteSamplers', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLsizei n, const GLuint* samplers', }, +{ 'return_type': 'void', 'names': ['glDeleteShader'], 'arguments': 'GLuint shader', }, { 'return_type': 'void', @@ -220,6 +291,10 @@ 'names': ['glDeleteTextures'], 'arguments': 'GLsizei n, const GLuint* textures', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glDeleteTransformFeedbacks', + 'gl_versions': ['gl4', 'es3'] }], + 'arguments': 'GLsizei n, const GLuint* ids', }, +{ 'return_type': 'void', 'known_as': 'glDeleteVertexArraysOES', 'versions': [{ 'name': 'glDeleteVertexArrays', 'gl_versions': ['gl3', 'gl4', 'es3'] }, @@ -285,6 +360,11 @@ 'GLenum mode, GLsizei count, GLenum type, const void* indices, ' 'GLsizei primcount', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glDrawRangeElements', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum mode, GLuint start, GLuint end, GLsizei count, ' + 'GLenum type, const void* indices', }, +{ 'return_type': 'void', 'names': ['glEGLImageTargetRenderbufferStorageOES'], 'arguments': 'GLenum target, GLeglImageOES image', }, { 'return_type': 'void', @@ -297,11 +377,16 @@ 'names': ['glEnableVertexAttribArray'], 'arguments': 'GLuint index', }, { 'return_type': 'void', - 'names': ['glEndQuery'], + 'versions': [{ 'name': 'glEndQuery', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], 'arguments': 'GLenum target', }, { 'return_type': 'void', 'names': ['glEndQueryARB', 'glEndQueryEXT'], 'arguments': 'GLenum target', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glEndTransformFeedback', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'void', }, { 'return_type': 'GLsync', 'names': ['glFenceSync'], 'arguments': 'GLenum condition, GLbitfield flags', }, @@ -343,6 +428,11 @@ 'GLenum target, GLenum attachment, GLenum textarget, GLuint texture, ' 'GLint level, GLsizei samples', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glFramebufferTextureLayer', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum target, GLenum attachment, GLuint texture, GLint level, ' + 'GLint layer', }, +{ 'return_type': 'void', 'names': ['glFrontFace'], 'arguments': 'GLenum mode', }, { 'return_type': 'void', @@ -363,7 +453,8 @@ 'names': ['glGenFramebuffersEXT', 'glGenFramebuffers'], 'arguments': 'GLsizei n, GLuint* framebuffers', }, { 'return_type': 'void', - 'names': ['glGenQueries'], + 'versions': [{ 'name': 'glGenQueries', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], 'arguments': 'GLsizei n, GLuint* ids', }, { 'return_type': 'void', 'names': ['glGenQueriesARB', 'glGenQueriesEXT'], @@ -372,9 +463,17 @@ 'names': ['glGenRenderbuffersEXT', 'glGenRenderbuffers'], 'arguments': 'GLsizei n, GLuint* renderbuffers', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGenSamplers', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLsizei n, GLuint* samplers', }, +{ 'return_type': 'void', 'names': ['glGenTextures'], 'arguments': 'GLsizei n, GLuint* textures', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGenTransformFeedbacks', + 'gl_versions': ['gl4', 'es3'] }], + 'arguments': 'GLsizei n, GLuint* ids', }, +{ 'return_type': 'void', 'known_as': 'glGenVertexArraysOES', 'versions': [{ 'name': 'glGenVertexArrays', 'gl_versions': ['gl3', 'gl4', 'es3'] }, @@ -395,6 +494,21 @@ 'GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, ' 'GLint* size, GLenum* type, char* name', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGetActiveUniformBlockiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.1 or higher. + 'arguments': 'GLuint program, GLuint uniformBlockIndex, GLenum pname, ' + 'GLint* params', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glGetActiveUniformBlockName', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.1 or higher. + 'arguments': 'GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, ' + 'GLsizei* length, char* uniformBlockName', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glGetActiveUniformsiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.1 or higher. + 'arguments': 'GLuint program, GLsizei uniformCount, ' + 'const GLuint* uniformIndices, GLenum pname, GLint* params', }, +{ 'return_type': 'void', 'names': ['glGetAttachedShaders'], 'arguments': 'GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders', }, @@ -419,6 +533,10 @@ { 'return_type': 'void', 'names': ['glGetFloatv'], 'arguments': 'GLenum pname, GLfloat* params', }, +{ 'return_type': 'GLint', + 'versions': [{ 'name': 'glGetFragDataLocation', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint program, const char* name', }, { 'return_type': 'void', 'names': ['glGetFramebufferAttachmentParameterivEXT', 'glGetFramebufferAttachmentParameteriv'], @@ -431,12 +549,25 @@ 'glGetGraphicsResetStatus'], 'arguments': 'void', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGetInteger64i_v', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLenum target, GLuint index, GLint64* data', }, +{ 'return_type': 'void', 'names': ['glGetInteger64v'], 'arguments': 'GLenum pname, GLint64* params', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGetIntegeri_v', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLenum target, GLuint index, GLint* data', }, +{ 'return_type': 'void', 'names': ['glGetIntegerv'], 'arguments': 'GLenum pname, GLint* params', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGetInternalformativ', + 'gl_versions': ['gl4', 'es3'] }], # GL 4.2 or higher. + 'arguments': 'GLenum target, GLenum internalformat, GLenum pname, ' + 'GLsizei bufSize, GLint* params', }, +{ 'return_type': 'void', 'known_as': 'glGetProgramBinary', 'versions': [{ 'name': 'glGetProgramBinaryOES' }, { 'name': 'glGetProgramBinary', @@ -452,7 +583,8 @@ 'names': ['glGetProgramiv'], 'arguments': 'GLuint program, GLenum pname, GLint* params', }, { 'return_type': 'void', - 'names': ['glGetQueryiv'], + 'versions': [{ 'name': 'glGetQueryiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], 'arguments': 'GLenum target, GLenum pname, GLint* params', }, { 'return_type': 'void', 'names': ['glGetQueryivARB', 'glGetQueryivEXT'], @@ -461,14 +593,18 @@ 'names': ['glGetQueryObjecti64v'], 'arguments': 'GLuint id, GLenum pname, GLint64* params', }, { 'return_type': 'void', - 'names': ['glGetQueryObjectiv', 'glGetQueryObjectivARB', - 'glGetQueryObjectivEXT'], + 'versions': [{ 'name': 'glGetQueryObjectiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint id, GLenum pname, GLint* params', }, +{ 'return_type': 'void', + 'names': ['glGetQueryObjectivARB', 'glGetQueryObjectivEXT'], 'arguments': 'GLuint id, GLenum pname, GLint* params', }, { 'return_type': 'void', 'names': ['glGetQueryObjectui64v', 'glGetQueryObjectui64vEXT'], 'arguments': 'GLuint id, GLenum pname, GLuint64* params', }, { 'return_type': 'void', - 'names': ['glGetQueryObjectuiv'], + 'versions': [{ 'name': 'glGetQueryObjectuiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], 'arguments': 'GLuint id, GLenum pname, GLuint* params', }, { 'return_type': 'void', 'names': ['glGetQueryObjectuivARB', 'glGetQueryObjectuivEXT'], @@ -477,6 +613,14 @@ 'names': ['glGetRenderbufferParameterivEXT', 'glGetRenderbufferParameteriv'], 'arguments': 'GLenum target, GLenum pname, GLint* params', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGetSamplerParameterfv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLuint sampler, GLenum pname, GLfloat* params', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glGetSamplerParameteriv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLuint sampler, GLenum pname, GLint* params', }, +{ 'return_type': 'void', 'names': ['glGetShaderInfoLog'], 'arguments': 'GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog', }, @@ -512,13 +656,27 @@ 'names': ['glGetTexParameteriv'], 'arguments': 'GLenum target, GLenum pname, GLint* params', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGetTransformFeedbackVarying', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint program, GLuint index, GLsizei bufSize, ' + 'GLsizei* length, GLenum* type, char* name', }, +{ 'return_type': 'void', 'names': ['glGetTranslatedShaderSourceANGLE'], 'arguments': 'GLuint shader, GLsizei bufsize, GLsizei* length, char* source', }, +{ 'return_type': 'GLuint', + 'versions': [{ 'name': 'glGetUniformBlockIndex', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.1 or higher. + 'arguments': 'GLuint program, const char* uniformBlockName', }, { 'return_type': 'void', 'names': ['glGetUniformfv'], 'arguments': 'GLuint program, GLint location, GLfloat* params', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glGetUniformIndices', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.1 or higher. + 'arguments': 'GLuint program, GLsizei uniformCount, ' + 'const char* const* uniformNames, GLuint* uniformIndices', }, +{ 'return_type': 'void', 'names': ['glGetUniformiv'], 'arguments': 'GLuint program, GLint location, GLint* params', }, { 'return_type': 'GLint', @@ -539,6 +697,12 @@ { 'return_type': 'void', 'names': ['glInsertEventMarkerEXT'], 'arguments': 'GLsizei length, const char* marker', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glInvalidateSubFramebuffer', + 'gl_versions': ['gl4', 'es3'] }], # GL 4.3 or higher. + 'arguments': + 'GLenum target, GLsizei numAttachments, const GLenum* attachments, ' + 'GLint x, GLint y, GLint width, GLint height', }, { 'return_type': 'GLboolean', 'names': ['glIsBuffer'], 'arguments': 'GLuint buffer', }, @@ -560,12 +724,20 @@ 'names': ['glIsProgram'], 'arguments': 'GLuint program', }, { 'return_type': 'GLboolean', + 'versions': [{ 'name': 'glIsQuery', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint query', }, +{ 'return_type': 'GLboolean', 'names': ['glIsQueryARB', 'glIsQueryEXT'], 'arguments': 'GLuint query', }, { 'return_type': 'GLboolean', 'names': ['glIsRenderbufferEXT', 'glIsRenderbuffer'], 'arguments': 'GLuint renderbuffer', }, { 'return_type': 'GLboolean', + 'versions': [{ 'name': 'glIsSampler', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLuint sampler', }, +{ 'return_type': 'GLboolean', 'names': ['glIsShader'], 'arguments': 'GLuint shader', }, { 'return_type': 'GLboolean', @@ -575,9 +747,13 @@ 'names': ['glIsTexture'], 'arguments': 'GLuint texture', }, { 'return_type': 'GLboolean', + 'versions': [{ 'name': 'glIsTransformFeedback', + 'gl_versions': ['gl4', 'es3'] }], + 'arguments': 'GLuint id', }, +{ 'return_type': 'GLboolean', 'known_as': 'glIsVertexArrayOES', 'versions': [{ 'name': 'glIsVertexArray', - 'gl_versions': ['gl3', 'gl4'] }, + 'gl_versions': ['gl3', 'gl4', 'es3'] }, { 'name': 'glIsVertexArray', 'extensions': ['GL_ARB_vertex_array_object'] }, { 'name': 'glIsVertexArrayOES' }, @@ -623,6 +799,10 @@ 'extensions': ['GL_NV_path_rendering'] }], 'arguments': 'GLenum matrixMode' }, { 'return_type': 'void', + 'versions': [{ 'name': 'glPauseTransformFeedback', + 'gl_versions': ['gl4', 'es3'] }], + 'arguments': 'void', }, +{ 'return_type': 'void', 'names': ['glPixelStorei'], 'arguments': 'GLenum pname, GLint param', }, { 'return_type': 'void', @@ -704,9 +884,29 @@ 'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, ' 'GLsizei width, GLsizei height', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glResumeTransformFeedback', + 'gl_versions': ['gl4', 'es3'] }], + 'arguments': 'void', }, +{ 'return_type': 'void', 'names': ['glSampleCoverage'], 'arguments': 'GLclampf value, GLboolean invert', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glSamplerParameterf', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLuint sampler, GLenum pname, GLfloat param', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glSamplerParameterfv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLuint sampler, GLenum pname, const GLfloat* params', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glSamplerParameteri', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLuint sampler, GLenum pname, GLint param', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glSamplerParameteriv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.2 or higher. + 'arguments': 'GLuint sampler, GLenum pname, const GLint* params', }, +{ 'return_type': 'void', 'names': ['glScissor'], 'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', }, { 'return_type': 'void', @@ -774,6 +974,13 @@ 'GLsizei height, GLint border, GLenum format, GLenum type, ' 'const void* pixels', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glTexImage3D', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': + 'GLenum target, GLint level, GLint internalformat, GLsizei width, ' + 'GLsizei height, GLsizei depth, GLint border, GLenum format, ' + 'GLenum type, const void* pixels', }, +{ 'return_type': 'void', 'names': ['glTexParameterf'], 'arguments': 'GLenum target, GLenum pname, GLfloat param', }, { 'return_type': 'void', @@ -796,11 +1003,29 @@ 'arguments': 'GLenum target, GLsizei levels, GLenum internalformat, ' 'GLsizei width, GLsizei height', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glTexStorage3D', + 'gl_versions': ['gl4', 'es3'] }], # GL 4.2 or higher. + 'arguments': 'GLenum target, GLsizei levels, GLenum internalformat, ' + 'GLsizei width, GLsizei height, GLsizei depth', }, +{ 'return_type': 'void', 'names': ['glTexSubImage2D'], 'arguments': 'GLenum target, GLint level, GLint xoffset, GLint yoffset, ' 'GLsizei width, GLsizei height, GLenum format, GLenum type, ' 'const void* pixels', }, +# TODO(zmo): wait for MOCK_METHOD11. +# { 'return_type': 'void', +# 'versions': [{ 'name': 'glTexSubImage3D', +# 'gl_versions': ['gl3', 'gl4', 'es3'] }], +# 'arguments': +# 'GLenum target, GLint level, GLint xoffset, GLint yoffset, ' +# 'GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, ' +# 'GLenum format, GLenum type, const void* pixels', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glTransformFeedbackVaryings', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint program, GLsizei count, const char* const* varyings, ' + 'GLenum bufferMode', }, { 'return_type': 'void', 'names': ['glUniform1f'], 'arguments': 'GLint location, GLfloat x', }, @@ -814,6 +1039,14 @@ 'names': ['glUniform1iv'], 'arguments': 'GLint location, GLsizei count, const GLint* v', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glUniform1ui', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLuint v0', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniform1uiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, const GLuint* v', }, +{ 'return_type': 'void', 'names': ['glUniform2f'], 'arguments': 'GLint location, GLfloat x, GLfloat y', }, { 'return_type': 'void', @@ -826,6 +1059,14 @@ 'names': ['glUniform2iv'], 'arguments': 'GLint location, GLsizei count, const GLint* v', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glUniform2ui', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLuint v0, GLuint v1', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniform2uiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, const GLuint* v', }, +{ 'return_type': 'void', 'names': ['glUniform3f'], 'arguments': 'GLint location, GLfloat x, GLfloat y, GLfloat z', }, { 'return_type': 'void', @@ -838,6 +1079,14 @@ 'names': ['glUniform3iv'], 'arguments': 'GLint location, GLsizei count, const GLint* v', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glUniform3ui', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLuint v0, GLuint v1, GLuint v2', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniform3uiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, const GLuint* v', }, +{ 'return_type': 'void', 'names': ['glUniform4f'], 'arguments': 'GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w', }, { 'return_type': 'void', @@ -850,17 +1099,60 @@ 'names': ['glUniform4iv'], 'arguments': 'GLint location, GLsizei count, const GLint* v', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glUniform4ui', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniform4uiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, const GLuint* v', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniformBlockBinding', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], # GL 3.1 or higher. + 'arguments': 'GLuint program, GLuint uniformBlockIndex, ' + 'GLuint uniformBlockBinding', }, +{ 'return_type': 'void', 'names': ['glUniformMatrix2fv'], 'arguments': 'GLint location, GLsizei count, ' 'GLboolean transpose, const GLfloat* value', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glUniformMatrix2x3fv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniformMatrix2x4fv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'void', 'names': ['glUniformMatrix3fv'], 'arguments': 'GLint location, GLsizei count, ' 'GLboolean transpose, const GLfloat* value', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glUniformMatrix3x2fv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniformMatrix3x4fv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'void', 'names': ['glUniformMatrix4fv'], 'arguments': 'GLint location, GLsizei count, ' 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniformMatrix4x2fv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glUniformMatrix4x3fv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLint location, GLsizei count, ' + 'GLboolean transpose, const GLfloat* value', }, { 'return_type': 'GLboolean', 'known_as': 'glUnmapBuffer', 'names': ['glUnmapBufferOES', 'glUnmapBuffer'], @@ -902,6 +1194,27 @@ 'arguments': 'GLuint index, GLuint divisor', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glVertexAttribI4i', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint indx, GLint x, GLint y, GLint z, GLint w', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glVertexAttribI4iv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint indx, const GLint* values', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glVertexAttribI4ui', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint indx, GLuint x, GLuint y, GLuint z, GLuint w', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glVertexAttribI4uiv', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint indx, const GLuint* values', }, +{ 'return_type': 'void', + 'versions': [{ 'name': 'glVertexAttribIPointer', + 'gl_versions': ['gl3', 'gl4', 'es3'] }], + 'arguments': 'GLuint indx, GLint size, GLenum type, GLsizei stride, ' + 'const void* ptr', }, +{ 'return_type': 'void', 'names': ['glVertexAttribPointer'], 'arguments': 'GLuint indx, GLint size, GLenum type, GLboolean normalized, ' 'GLsizei stride, const void* ptr', },
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h index aea47fc..595a31f 100644 --- a/ui/gl/gl_bindings.h +++ b/ui/gl/gl_bindings.h
@@ -116,17 +116,17 @@ #define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 // GL_CHROMIUM_command_buffer_query -#define GL_COMMANDS_ISSUED_CHROMIUM 0x84F2 +#define GL_COMMANDS_ISSUED_CHROMIUM 0x6004 /* GL_CHROMIUM_get_error_query */ -#define GL_GET_ERROR_QUERY_CHROMIUM 0x84F3 +#define GL_GET_ERROR_QUERY_CHROMIUM 0x6003 /* GL_CHROMIUM_command_buffer_latency_query */ -#define GL_LATENCY_QUERY_CHROMIUM 0x84F4 +#define GL_LATENCY_QUERY_CHROMIUM 0x6007 /* GL_CHROMIUM_async_pixel_transfers */ -#define GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM 0x84F5 -#define GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM 0x84F6 +#define GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM 0x6005 +#define GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM 0x6006 // GL_CHROMIUM_sync_query #define GL_COMMANDS_COMPLETED_CHROMIUM 0x84F7
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc index a752940..0a67e00 100644 --- a/ui/gl/gl_image_memory.cc +++ b/ui/gl/gl_image_memory.cc
@@ -179,15 +179,11 @@ return false; DCHECK(memory_); - glTexImage2D(target, - 0, // mip level - TextureFormat(format_), - size_.width(), - size_.height(), - 0, // border - DataFormat(format_), - DataType(format_), - memory_); + glTexSubImage2D(target, 0, // level + 0, // x + 0, // y + size_.width(), size_.height(), DataFormat(format_), + DataType(format_), memory_); return true; }
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc index 4459d48..00e224d 100644 --- a/ui/gl/gl_surface.cc +++ b/ui/gl/gl_surface.cc
@@ -166,6 +166,10 @@ return true; } +void GLSurface::DestroyAndTerminateDisplay() { + Destroy(); +} + bool GLSurface::Resize(const gfx::Size& size) { NOTIMPLEMENTED(); return false;
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h index d458063..1351638 100644 --- a/ui/gl/gl_surface.h +++ b/ui/gl/gl_surface.h
@@ -38,6 +38,10 @@ // Destroys the surface. virtual void Destroy() = 0; + // Destroys the surface and terminates its underlying display. This must be + // the last surface which uses the display. + virtual void DestroyAndTerminateDisplay(); + virtual bool Resize(const gfx::Size& size); // Recreate the surface without changing the size.
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc index 19119a9..3a453b6 100644 --- a/ui/gl/gl_surface_egl.cc +++ b/ui/gl/gl_surface_egl.cc
@@ -61,7 +61,16 @@ EGLConfig g_config; EGLDisplay g_display; -EGLNativeDisplayType g_native_display; +EGLNativeDisplayType g_native_display_type; + +// In the Cast environment, we need to destroy the EGLNativeDisplayType and +// EGLDisplay returned by the GPU platform when we switch to an external app +// which will temporarily own all screen and GPU resources. +// Even though Chromium is still in the background. +// As such, it must be reinitialized each time we come back to the foreground. +bool g_initialized = false; +int g_num_surfaces = 0; +bool g_terminate_pending = false; const char* g_egl_extensions = NULL; bool g_egl_create_context_robustness_supported = false; @@ -105,21 +114,34 @@ DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider); }; +void DeinitializeEgl() { + if (g_initialized) { + g_initialized = false; + eglTerminate(g_display); + } +} + } // namespace -GLSurfaceEGL::GLSurfaceEGL() {} +GLSurfaceEGL::GLSurfaceEGL() { + ++g_num_surfaces; + if (!g_initialized) { + bool result = GLSurfaceEGL::InitializeOneOff(); + DCHECK(result); + DCHECK(g_initialized); + } +} bool GLSurfaceEGL::InitializeOneOff() { - static bool initialized = false; - if (initialized) + if (g_initialized) return true; - g_native_display = GetPlatformDefaultEGLNativeDisplay(); + g_native_display_type = GetPlatformDefaultEGLNativeDisplay(); #if defined(OS_WIN) - g_display = GetPlatformDisplay(g_native_display); + g_display = GetPlatformDisplay(g_native_display_type); #else - g_display = eglGetDisplay(g_native_display); + g_display = eglGetDisplay(g_native_display_type); #endif if (!g_display) { @@ -187,6 +209,12 @@ g_egl_window_fixed_size_supported = HasEGLExtension("EGL_ANGLE_window_fixed_size"); + // We always succeed beyond this point so set g_initialized here to avoid + // infinite recursion through CreateGLContext and GetDisplay + // if g_egl_surfaceless_context_supported. + g_initialized = true; + g_terminate_pending = false; + // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary // workaround, since code written for Android WebView takes different paths // based on whether GL surface objects have underlying EGL surface handles, @@ -216,24 +244,35 @@ } #endif - initialized = true; - return true; } EGLDisplay GLSurfaceEGL::GetDisplay() { + DCHECK(g_initialized); return g_display; } +// static EGLDisplay GLSurfaceEGL::GetHardwareDisplay() { + if (!g_initialized) { + bool result = GLSurfaceEGL::InitializeOneOff(); + DCHECK(result); + } return g_display; } +// static EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() { - return g_native_display; + if (!g_initialized) { + bool result = GLSurfaceEGL::InitializeOneOff(); + DCHECK(result); + } + return g_native_display_type; } const char* GLSurfaceEGL::GetEGLExtensions() { + // No need for InitializeOneOff. Assume that extensions will not change + // after the first initialization. return g_egl_extensions; } @@ -249,7 +288,20 @@ return g_egl_surfaceless_context_supported; } -GLSurfaceEGL::~GLSurfaceEGL() {} +void GLSurfaceEGL::DestroyAndTerminateDisplay() { + DCHECK(g_initialized); + DCHECK_EQ(g_num_surfaces, 1); + Destroy(); + g_terminate_pending = true; +} + +GLSurfaceEGL::~GLSurfaceEGL() { + DCHECK_GT(g_num_surfaces, 0) << "Bad surface count"; + if (--g_num_surfaces == 0 && g_terminate_pending) { + DeinitializeEgl(); + g_terminate_pending = false; + } +} #if defined(OS_WIN) static const EGLint kDisplayAttribsWarp[] {
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h index 952ccad..720c7dd 100644 --- a/ui/gl/gl_surface_egl.h +++ b/ui/gl/gl_surface_egl.h
@@ -29,6 +29,7 @@ GLSurfaceEGL(); // Implement GLSurface. + void DestroyAndTerminateDisplay() override; EGLDisplay GetDisplay() override; static bool InitializeOneOff();