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();