I've been looking into the same thing recently. There's a good explanation of the Android graphics stack internals here:
https://source.android.com/devices/graphics/architecture.html
Essentially SurfaceViews on android represent the producer end of a buffer queue. The consumer of those buffers is SurfaceFlinger which handles updating the surfaces being displayed on the next vsync. The key thing is that this is a queue. Doing eglSwapBuffers in fact doesn't block unless the queue is full. That means if your rendering is simple, GLSurfaceView renders the first couple of frames very quickly, filling the buffer queue, and then settles down into the "render every 16ms" steady state.
You can see the number of filled buffers in the queue with systrace. You'll notice the GLSurfaceView typically starts a vsync period with 1 frame in the queue, when your render function finishes this goes up to 2, meaning you will need to wait for 2 vsyncs before it displays (in fact 3, I think, because SurfaceFlinger adds another for composition, but that's the same for everyone).
Canvas is drawn on demand rather than continuously, and as that drawing typically happens at much less than the display update rate the BufferQueue for that window is typically empty so new content is consumed immediately by SurfaceFlinger on the next vsync.
You can register for callbacks on vsync so you never render more than the display refresh rate. That avoids the "fill the queue as fast as possible" effect of GLSurfaceView's continuous rendering. However I'm not sure that guarantees the queue will not fill up as it is possible that SurfaceFlinger will skip a beat, causing your queue to grow anyway. I've got a question on that here:
Minimize Android GLSurfaceView lag
I've done a test where I render on vsync, but skip a few frames every few hundred to guarantee the queue empties properly. In that case the GL-rendered objects do move in lock-step with the "pointer trail" overlay crosshair. The "debug circle" appears to still be slightly ahead - I think that is implemented as a simple layer reposition during SurfaceFlinger's composition of the drawn surfaces which would put it an additional frame ahead of the other rendering.