@Override public void didFirstVisuallyNonEmptyPaint() { RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers.next().didFirstVisuallyNonEmptyPaint(mTab); } }
@Override public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) { if (mNeedToRender) { if (mPendingSwapBuffers + mPendingRenders <= MAX_SWAP_BUFFER_COUNT) { mNeedToRender = false; mPendingRenders++; render(); } else { TraceEvent.instant("ContentViewRenderView:bail"); } } if (mVSyncListener != null) { if (mVSyncNotificationEnabled) { for (mCurrentVSyncListenersIterator.rewind(); mCurrentVSyncListenersIterator.hasNext(); ) { mCurrentVSyncListenersIterator.next().onVSync(vsyncTimeMicros); } mVSyncMonitor.requestUpdate(); } else { // Compensate for input event lag. Input events are delivered immediately on // pre-JB releases, so this adjustment is only done for later versions. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { vsyncTimeMicros += INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS; } mVSyncListener.updateVSync(vsyncTimeMicros, mVSyncMonitor.getVSyncPeriodInMicroseconds()); } } }
@Override public void didStartNavigationToPendingEntry(String url) { RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers.next().onDidStartNavigationToPendingEntry(mTab, url); } }
@Override public void didFailLoad( boolean isProvisionalLoad, boolean isMainFrame, int errorCode, String description, String failingUrl, boolean wasIgnoredByHandler) { RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers .next() .onDidFailLoad(mTab, isProvisionalLoad, isMainFrame, errorCode, description, failingUrl); } if (isMainFrame) mTab.didFailPageLoad(errorCode); PolicyAuditor auditor = ((ChromeApplication) mTab.getApplicationContext()).getPolicyAuditor(); auditor.notifyAuditEvent( mTab.getApplicationContext(), AuditEvent.OPEN_URL_FAILURE, failingUrl, description); if (errorCode == BLOCKED_BY_ADMINISTRATOR) { auditor.notifyAuditEvent( mTab.getApplicationContext(), AuditEvent.OPEN_URL_BLOCKED, failingUrl, ""); } }
@Override public void buildContextMenu(ContextMenu menu, Context context, ContextMenuParams params) { mPopulator.buildContextMenu(menu, context, params); RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers.next().onContextMenuShown(mTab, menu); } }
@Override public void didCommitProvisionalLoadForFrame( long frameId, boolean isMainFrame, String url, int transitionType) { if (isMainFrame && UmaUtils.isRunningApplicationStart()) { // Currently it takes about 2000ms to commit a navigation if the measurement // begins very early in the browser start. How many buckets (b) are needed to // explore the _typical_ values with granularity 100ms and a maximum duration // of 1 minute? // s^{n+1} / s^{n} = 2100 / 2000 // s = 1.05 // s^b = 60000 // b = ln(60000) / ln(1.05) ~= 225 RecordHistogram.recordCustomTimesHistogram( "Startup.FirstCommitNavigationTime", SystemClock.uptimeMillis() - UmaUtils.getMainEntryPointTime(), 1, 60000 /* 1 minute */, TimeUnit.MILLISECONDS, 225); UmaUtils.setRunningApplicationStart(false); } if (isMainFrame) { mTab.setIsTabStateDirty(true); mTab.updateTitle(); } RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers .next() .onDidCommitProvisionalLoadForFrame(mTab, frameId, isMainFrame, url, transitionType); } observers.rewind(); while (observers.hasNext()) { observers.next().onUrlUpdated(mTab); } if (!isMainFrame) return; mTab.handleDidCommitProvisonalLoadForFrame(url, transitionType); }
@Override public void didDetachInterstitialPage() { mTab.getInfoBarContainer().setVisibility(View.VISIBLE); didChangeThemeColor(mTab.getWebContents().getThemeColor(mTab.getDefaultThemeColor())); RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers.next().onDidDetachInterstitialPage(mTab); } mTab.notifyLoadProgress(mTab.getProgress()); mTab.updateFullscreenEnabledState(); if (!mTab.maybeShowNativePage(mTab.getUrl(), false)) { mTab.showRenderedPage(); } }
@Override public void didStartProvisionalLoadForFrame( long frameId, long parentFrameId, boolean isMainFrame, String validatedUrl, boolean isErrorPage, boolean isIframeSrcdoc) { if (isMainFrame) mTab.didStartPageLoad(validatedUrl, isErrorPage); RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers .next() .onDidStartProvisionalLoadForFrame( mTab, frameId, parentFrameId, isMainFrame, validatedUrl, isErrorPage, isIframeSrcdoc); } }
@Override public void didAttachInterstitialPage() { mTab.getInfoBarContainer().setVisibility(View.INVISIBLE); mTab.showRenderedPage(); didChangeThemeColor(mTab.getDefaultThemeColor()); RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers.next().onDidAttachInterstitialPage(mTab); } mTab.notifyLoadProgress(mTab.getProgress()); mTab.updateFullscreenEnabledState(); PolicyAuditor auditor = ((ChromeApplication) mTab.getApplicationContext()).getPolicyAuditor(); auditor.notifyCertificateFailure( PolicyAuditor.nativeGetCertificateFailure(mTab.getWebContents()), mTab.getApplicationContext()); }
@Override public void didChangeThemeColor(int color) { int securityLevel = mTab.getSecurityLevel(); if (securityLevel == ConnectionSecurityLevel.SECURITY_ERROR || securityLevel == ConnectionSecurityLevel.SECURITY_WARNING || securityLevel == ConnectionSecurityLevel.SECURITY_POLICY_WARNING) { color = mTab.getDefaultThemeColor(); } if (mTab.isShowingInterstitialPage()) color = mTab.getDefaultThemeColor(); if (!isThemeColorEnabled(mTab.getApplicationContext())) { color = mTab.getDefaultThemeColor(); } if (color == Color.TRANSPARENT) color = mTab.getDefaultThemeColor(); if (mTab.isIncognito()) color = mTab.getDefaultThemeColor(); color |= 0xFF000000; if (mTab.getThemeColor() == color) return; mThemeColor = color; RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers.next().onDidChangeThemeColor(mTab, mTab.getThemeColor()); } }
@Override public void didNavigateMainFrame( String url, String baseUrl, boolean isNavigationToDifferentPage, boolean isFragmentNavigation, int statusCode) { FullscreenManager fullscreenManager = mTab.getFullscreenManager(); if (isNavigationToDifferentPage && fullscreenManager != null) { fullscreenManager.setPersistentFullscreenMode(false); } RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers .next() .onDidNavigateMainFrame( mTab, url, baseUrl, isNavigationToDifferentPage, isFragmentNavigation, statusCode); } mTab.stopSwipeRefreshHandler(); }
@Override public void renderProcessGone(boolean processWasOomProtected) { Log.i( TAG, "renderProcessGone() for tab id: " + mTab.getId() + ", oom protected: " + Boolean.toString(processWasOomProtected) + ", already needs reload: " + Boolean.toString(mTab.needsReload())); // Do nothing for subsequent calls that happen while the tab remains crashed. This // can occur when the tab is in the background and it shares the renderer with other // tabs. After the renderer crashes, the WebContents of its tabs are still around // and they still share the RenderProcessHost. When one of the tabs reloads spawning // a new renderer for the shared RenderProcessHost and the new renderer crashes // again, all tabs sharing this renderer will be notified about the crash (including // potential background tabs that did not reload yet). if (mTab.needsReload() || mTab.isShowingSadTab()) return; // This will replace TabRendererCrashStatus if numbers line up. int appState = ApplicationStatus.getStateForApplication(); boolean applicationRunning = (appState == ApplicationState.HAS_RUNNING_ACTIVITIES); boolean applicationPaused = (appState == ApplicationState.HAS_PAUSED_ACTIVITIES); @TabRendererExitStatus int rendererExitStatus = TAB_RENDERER_EXIT_STATUS_MAX; if (processWasOomProtected) { if (applicationRunning) { rendererExitStatus = TAB_RENDERER_EXIT_STATUS_OOM_PROTECTED_IN_RUNNING_APP; } else if (applicationPaused) { rendererExitStatus = TAB_RENDERER_EXIT_STATUS_OOM_PROTECTED_IN_PAUSED_APP; } else { rendererExitStatus = TAB_RENDERER_EXIT_STATUS_OOM_PROTECTED_IN_BACKGROUND_APP; } } else { if (applicationRunning) { rendererExitStatus = TAB_RENDERER_EXIT_STATUS_NOT_PROTECTED_IN_RUNNING_APP; } else if (applicationPaused) { rendererExitStatus = TAB_RENDERER_EXIT_STATUS_NOT_PROTECTED_IN_PAUSED_APP; } else { rendererExitStatus = TAB_RENDERER_EXIT_STATUS_NOT_PROTECTED_IN_BACKGROUND_APP; } } RecordHistogram.recordEnumeratedHistogram( "Tab.RendererExitStatus", rendererExitStatus, TAB_RENDERER_EXIT_STATUS_MAX); int activityState = ApplicationStatus.getStateForActivity(mTab.getWindowAndroid().getActivity().get()); int rendererCrashStatus = TAB_RENDERER_CRASH_STATUS_MAX; if (!processWasOomProtected || activityState == ActivityState.PAUSED || activityState == ActivityState.STOPPED || activityState == ActivityState.DESTROYED) { // The tab crashed in background or was killed by the OS out-of-memory killer. // setNeedsReload(true); mTab.setNeedsReload(true); if (applicationRunning) { rendererCrashStatus = TAB_RENDERER_CRASH_STATUS_HIDDEN_IN_FOREGROUND_APP; } else { rendererCrashStatus = TAB_RENDERER_CRASH_STATUS_HIDDEN_IN_BACKGROUND_APP; } } else { rendererCrashStatus = TAB_RENDERER_CRASH_STATUS_SHOWN_IN_FOREGROUND_APP; mTab.showSadTab(); // This is necessary to correlate histogram data with stability counts. UmaSessionStats.logRendererCrash(); } RecordHistogram.recordEnumeratedHistogram( "Tab.RendererCrashStatus", rendererCrashStatus, TAB_RENDERER_CRASH_STATUS_MAX); mTab.handleTabCrash(); boolean sadTabShown = mTab.isShowingSadTab(); RewindableIterator<TabObserver> observers = mTab.getTabObservers(); while (observers.hasNext()) { observers.next().onCrash(mTab, sadTabShown); } }