Index: components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java |
diff --git a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java b/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java |
deleted file mode 100644 |
index 11fd9b6f0738b1e511cba714c300f3ef7233422b..0000000000000000000000000000000000000000 |
--- a/components/devtools_bridge/android/java/src/org/chromium/components/devtools_bridge/SessionBase.java |
+++ /dev/null |
@@ -1,435 +0,0 @@ |
-// 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. |
- |
-package org.chromium.components.devtools_bridge; |
- |
-import java.nio.ByteBuffer; |
-import java.util.ArrayList; |
-import java.util.HashMap; |
-import java.util.List; |
-import java.util.Map; |
- |
-/** |
- * Base class for ServerSession and ClientSession. Both opens a control channel and a default |
- * tunnel. Control channel designated to exchange messages defined in SessionControlMessages. |
- * |
- * Signaling communication between client and server works in request/response manner. It's more |
- * restrictive than traditional bidirectional signaling channel but give more freedom in |
- * implementing signaling. Main motivation is that GCD provides API what works in that way. |
- * |
- * Session is initiated by a client. It creates an offer and sends it along with RTC configuration. |
- * Server sends an answer in response. Once session negotiated client starts ICE candidates |
- * exchange. It periodically sends own candidates and peeks server's ones. Periodic ICE exchange |
- * stops when control channel opens. It resumes if connections state turns to DISCONNECTED (because |
- * server may generate ICE candidates to recover connectivity but may not notify through |
- * control channel). ICE exchange in CONNECTED state designated to let improve connection |
- * when network configuration changed. |
- * |
- * If session is not started (or resumed) after mAutoCloseTimeoutMs it closes itself. |
- * |
- * Only default tunnel is supported at the moment. It designated for DevTools UNIX socket. |
- * Additional tunnels may be useful for: 1) reverse port forwarding and 2) tunneling |
- * WebView DevTools sockets of other applications. Additional tunnels negotiation should |
- * be implemented by adding new types of control messages. Dynamic tunnel configuration |
- * will need support for session renegotiation. |
- * |
- * Session is a single threaded object. Until started owner is responsible to synchronizing access |
- * to it. When started it must be called on the thread of SessionBase.Executor. |
- * All WebRTC callbacks are forwarded on this thread. |
- */ |
-public abstract class SessionBase { |
- private static final int CONTROL_CHANNEL_ID = 0; |
- private static final int DEFAULT_TUNNEL_CHANNEL_ID = 1; |
- |
- private final Executor mExecutor; |
- protected final SessionDependencyFactory mFactory; |
- private AbstractPeerConnection mConnection; |
- private AbstractDataChannel mControlChannel; |
- private List<String> mCandidates = new ArrayList<String>(); |
- private boolean mControlChannelOpened = false; |
- private boolean mConnected = false; |
- private Cancellable mAutoCloseTask; |
- private SessionControlMessages.MessageHandler mControlMessageHandler; |
- private final Map<Integer, SocketTunnel> mTunnels = |
- new HashMap<Integer, SocketTunnel>(); |
- private EventListener mEventListener; |
- |
- protected int mAutoCloseTimeoutMs = 30000; |
- |
- /** |
- * Allows to post tasks on the thread where the sessions lives. |
- */ |
- public interface Executor { |
- Cancellable postOnSessionThread(int delayMs, Runnable runnable); |
- boolean isCalledOnSessionThread(); |
- } |
- |
- /** |
- * Interface for cancelling scheduled tasks. |
- */ |
- public interface Cancellable { |
- void cancel(); |
- } |
- |
- /** |
- * Representation of server session. All methods are delivered through |
- * signaling channel (except test configurations). Server session is accessible |
- * in request/response manner. |
- */ |
- public interface ServerSessionInterface { |
- /** |
- * Starts session with specified RTC configuration and offer. |
- */ |
- void startSession(RTCConfiguration config, |
- String offer, |
- NegotiationCallback callback); |
- |
- /** |
- * Renegoteates session. Needed when tunnels added/removed on the fly. |
- */ |
- void renegotiate(String offer, NegotiationCallback callback); |
- |
- /** |
- * Sends client's ICE candidates to the server and peeks server's ICE candidates. |
- */ |
- void iceExchange(List<String> clientCandidates, IceExchangeCallback callback); |
- } |
- |
- /** |
- * Base interface for server callbacks. |
- */ |
- public interface ServerCallback { |
- void onFailure(String errorMessage); |
- } |
- |
- /** |
- * Server's response to startSession and renegotiate methods. |
- */ |
- public interface NegotiationCallback extends ServerCallback { |
- void onSuccess(String answer); |
- } |
- |
- /** |
- * Server's response on iceExchange method. |
- */ |
- public interface IceExchangeCallback extends ServerCallback { |
- void onSuccess(List<String> serverCandidates); |
- } |
- |
- /** |
- * Listener of session's events. |
- */ |
- public interface EventListener { |
- void onCloseSelf(); |
- } |
- |
- protected SessionBase(SessionDependencyFactory factory, |
- Executor executor, |
- SocketTunnel defaultTunnel) { |
- mExecutor = executor; |
- mFactory = factory; |
- addTunnel(DEFAULT_TUNNEL_CHANNEL_ID, defaultTunnel); |
- } |
- |
- public final void dispose() { |
- checkCalledOnSessionThread(); |
- |
- if (isStarted()) stop(); |
- |
- for (SocketTunnel tunnel : mTunnels.values()) { |
- tunnel.dispose(); |
- } |
- } |
- |
- public void setEventListener(EventListener listener) { |
- checkCalledOnSessionThread(); |
- |
- mEventListener = listener; |
- } |
- |
- protected AbstractPeerConnection connection() { |
- return mConnection; |
- } |
- |
- protected boolean doesTunnelExist(int channelId) { |
- return mTunnels.containsKey(channelId); |
- } |
- |
- private final void addTunnel(int channelId, SocketTunnel tunnel) { |
- assert !mTunnels.containsKey(channelId); |
- assert !tunnel.isBound(); |
- // Tunnel renegotiation not implemented. |
- assert channelId == DEFAULT_TUNNEL_CHANNEL_ID && !isStarted(); |
- |
- mTunnels.put(channelId, tunnel); |
- } |
- |
- protected void removeTunnel(int channelId) { |
- assert mTunnels.containsKey(channelId); |
- mTunnels.get(channelId).unbind().dispose(); |
- mTunnels.remove(channelId); |
- } |
- |
- protected final boolean isControlChannelOpened() { |
- return mControlChannelOpened; |
- } |
- |
- protected final boolean isConnected() { |
- return mConnected; |
- } |
- |
- protected final void postOnSessionThread(Runnable runnable) { |
- postOnSessionThread(0, runnable); |
- } |
- |
- protected final Cancellable postOnSessionThread(int delayMs, Runnable runnable) { |
- return mExecutor.postOnSessionThread(delayMs, runnable); |
- } |
- |
- protected final void checkCalledOnSessionThread() { |
- assert mExecutor.isCalledOnSessionThread(); |
- } |
- |
- public final boolean isStarted() { |
- return mConnection != null; |
- } |
- |
- /** |
- * Creates and configures peer connection and sets a control message handler. |
- */ |
- protected void start(RTCConfiguration config, |
- SessionControlMessages.MessageHandler handler) { |
- assert !isStarted(); |
- |
- mConnection = mFactory.createPeerConnection(config, new ConnectionObserver()); |
- mControlChannel = mConnection.createDataChannel(CONTROL_CHANNEL_ID); |
- mControlMessageHandler = handler; |
- mControlChannel.registerObserver(new ControlChannelObserver()); |
- |
- for (Map.Entry<Integer, SocketTunnel> entry : mTunnels.entrySet()) { |
- int channelId = entry.getKey(); |
- SocketTunnel tunnel = entry.getValue(); |
- tunnel.bind(connection().createDataChannel(channelId)); |
- } |
- } |
- |
- /** |
- * Disposed objects created in |start|. |
- */ |
- public void stop() { |
- checkCalledOnSessionThread(); |
- |
- assert isStarted(); |
- |
- stopAutoCloseTimer(); |
- |
- for (SocketTunnel tunnel : mTunnels.values()) { |
- tunnel.unbind().dispose(); |
- } |
- |
- AbstractPeerConnection connection = mConnection; |
- mConnection = null; |
- assert !isStarted(); |
- |
- mControlChannel.unregisterObserver(); |
- mControlMessageHandler = null; |
- mControlChannel.dispose(); |
- mControlChannel = null; |
- |
- // Dispose connection after data channels. |
- connection.dispose(); |
- } |
- |
- protected abstract void onRemoteDescriptionSet(); |
- protected abstract void onLocalDescriptionCreatedAndSet( |
- AbstractPeerConnection.SessionDescriptionType type, String description); |
- protected abstract void onControlChannelOpened(); |
- |
- protected void onControlChannelClosed() { |
- closeSelf(); |
- } |
- |
- protected void onIceConnectionChange() {} |
- |
- private void handleFailureOnSignalingThread(final String message) { |
- postOnSessionThread(new Runnable() { |
- @Override |
- public void run() { |
- if (isStarted()) |
- onFailure(message); |
- } |
- }); |
- } |
- |
- protected final void startAutoCloseTimer() { |
- assert mAutoCloseTask == null; |
- assert isStarted(); |
- mAutoCloseTask = postOnSessionThread(mAutoCloseTimeoutMs, new Runnable() { |
- @Override |
- public void run() { |
- assert isStarted(); |
- |
- mAutoCloseTask = null; |
- closeSelf(); |
- } |
- }); |
- } |
- |
- protected final void stopAutoCloseTimer() { |
- if (mAutoCloseTask != null) { |
- mAutoCloseTask.cancel(); |
- mAutoCloseTask = null; |
- } |
- } |
- |
- protected void closeSelf() { |
- stop(); |
- if (mEventListener != null) { |
- mEventListener.onCloseSelf(); |
- } |
- } |
- |
- // Returns collected candidates (for sending to the remote session) and removes them. |
- protected List<String> takeIceCandidates() { |
- List<String> result = new ArrayList<String>(); |
- result.addAll(mCandidates); |
- mCandidates.clear(); |
- return result; |
- } |
- |
- protected void addIceCandidates(List<String> candidates) { |
- for (String candidate : candidates) { |
- mConnection.addIceCandidate(candidate); |
- } |
- } |
- |
- protected void onFailure(String message) { |
- closeSelf(); |
- } |
- |
- protected void onIceCandidate(String candidate) { |
- mCandidates.add(candidate); |
- } |
- |
- /** |
- * Receives callbacks from the peer connection on the signaling thread. Forwards them |
- * on the session thread. All session event handling methods assume session started (prevents |
- * disposed objects). It drops callbacks it closed. |
- */ |
- private final class ConnectionObserver implements AbstractPeerConnection.Observer { |
- @Override |
- public void onFailure(final String description) { |
- postOnSessionThread(new Runnable() { |
- @Override |
- public void run() { |
- if (!isStarted()) return; |
- SessionBase.this.onFailure(description); |
- } |
- }); |
- } |
- |
- @Override |
- public void onLocalDescriptionCreatedAndSet( |
- final AbstractPeerConnection.SessionDescriptionType type, |
- final String description) { |
- postOnSessionThread(new Runnable() { |
- @Override |
- public void run() { |
- if (!isStarted()) return; |
- SessionBase.this.onLocalDescriptionCreatedAndSet(type, description); |
- } |
- }); |
- } |
- |
- @Override |
- public void onRemoteDescriptionSet() { |
- postOnSessionThread(new Runnable() { |
- @Override |
- public void run() { |
- if (!isStarted()) return; |
- SessionBase.this.onRemoteDescriptionSet(); |
- } |
- }); |
- } |
- |
- @Override |
- public void onIceCandidate(final String candidate) { |
- postOnSessionThread(new Runnable() { |
- @Override |
- public void run() { |
- if (!isStarted()) return; |
- SessionBase.this.onIceCandidate(candidate); |
- } |
- }); |
- } |
- |
- @Override |
- public void onIceConnectionChange(final boolean connected) { |
- postOnSessionThread(new Runnable() { |
- @Override |
- public void run() { |
- if (!isStarted()) return; |
- mConnected = connected; |
- SessionBase.this.onIceConnectionChange(); |
- } |
- }); |
- } |
- } |
- |
- /** |
- * Receives callbacks from the control channel. Forwards them on the session thread. |
- */ |
- private final class ControlChannelObserver implements AbstractDataChannel.Observer { |
- @Override |
- public void onStateChange(final AbstractDataChannel.State state) { |
- postOnSessionThread(new Runnable() { |
- @Override |
- public void run() { |
- if (!isStarted()) return; |
- mControlChannelOpened = state == AbstractDataChannel.State.OPEN; |
- |
- if (mControlChannelOpened) { |
- onControlChannelOpened(); |
- } else { |
- onControlChannelClosed(); |
- } |
- } |
- }); |
- } |
- |
- @Override |
- public void onMessage(ByteBuffer message) { |
- final byte[] bytes = new byte[message.remaining()]; |
- message.get(bytes); |
- postOnSessionThread(new Runnable() { |
- @Override |
- public void run() { |
- if (!isStarted() || mControlMessageHandler == null) return; |
- |
- try { |
- mControlMessageHandler.readMessage(bytes); |
- } catch (SessionControlMessages.InvalidFormatException e) { |
- // TODO(serya): handle |
- } |
- } |
- }); |
- } |
- } |
- |
- protected void sendControlMessage(SessionControlMessages.Message<?> message) { |
- assert mControlChannelOpened; |
- |
- byte[] bytes = SessionControlMessages.toByteArray(message); |
- ByteBuffer rawMessage = ByteBuffer.allocateDirect(bytes.length); |
- rawMessage.put(bytes); |
- |
- sendControlMessage(rawMessage); |
- } |
- |
- private void sendControlMessage(ByteBuffer rawMessage) { |
- rawMessage.limit(rawMessage.position()); |
- rawMessage.position(0); |
- mControlChannel.send(rawMessage, AbstractDataChannel.MessageType.TEXT); |
- } |
-} |