@Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] parameters = getIntent().getStringArrayExtra(EXTRAS); if (parameters != null) { for (String s : parameters) { s = s.replace("\\,", ","); } } if (Intent.ACTION_VIEW.equals(getIntent().getAction())) { Uri uri = getIntent().getData(); if (uri != null) { Log.i(TAG, "MojoShellActivity opening " + uri); if (parameters == null) { parameters = new String[] {uri.toString()}; } else { String[] newParameters = new String[parameters.length + 1]; System.arraycopy(parameters, 0, newParameters, 0, parameters.length); newParameters[parameters.length] = uri.toString(); parameters = newParameters; } } } // TODO(ppi): Gotcha - the call below will work only once per process lifetime, but the OS // has no obligation to kill the application process between destroying and restarting the // activity. If the application process is kept alive, initialization parameters sent with // the intent will be stale. // TODO(qsr): We should be passing application context here as required by // InitApplicationContext on the native side. Currently we can't, as PlatformViewportAndroid // relies on this being the activity context. ShellMain.ensureInitialized(this, parameters); ShellMain.start(); }
@Override @SuppressFBWarnings("DM_EXIT") public void onDestroy() { Log.i(TAG, "Destroying ChildProcessService pid=%d", Process.myPid()); super.onDestroy(); if (mActivitySemaphore.tryAcquire()) { // TODO(crbug.com/457406): This is a bit hacky, but there is no known better solution // as this service will get reused (at least if not sandboxed). // In fact, we might really want to always exit() from onDestroy(), not just from // the early return here. System.exit(0); return; } synchronized (mMainThread) { try { while (!mLibraryInitialized) { // Avoid a potential race in calling through to native code before the library // has loaded. mMainThread.wait(); } } catch (InterruptedException e) { // Ignore } } // Try to shutdown the MainThread gracefully, but it might not // have chance to exit normally. nativeShutdownMainThread(); }
/** * Installs secondary dexes if possible. * * <p>Isolated processes (e.g. renderer processes) can't load secondary dex files on K and below, * so we don't even try in that case. * * @param context The application context. */ @VisibleForTesting public static void install(Context context) { try { // TODO(jbudorick): Back out this version check once support for K & below works. // http://crbug.com/512357 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && processIsIsolated()) { Log.i(TAG, "Skipping multidex installation: inside isolated process."); } else { MultiDex.install(context); Log.i(TAG, "Completed multidex installation."); } } catch (NoSuchMethodException e) { Log.wtf(TAG, "Failed multidex installation", e); } catch (IllegalAccessException e) { Log.wtf(TAG, "Failed multidex installation", e); } catch (InvocationTargetException e) { Log.wtf(TAG, "Failed multidex installation", e); } }
/** * * Creates a BluetoothAdapterWrapper using the default android.bluetooth.BluetoothAdapter. May * fail if the default adapter is not available or if the application does not have sufficient * permissions. */ @CalledByNative public static BluetoothAdapterWrapper createWithDefaultAdapter(Context context) { final boolean hasPermissions = context.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED && context.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH_ADMIN) == PackageManager.PERMISSION_GRANTED; if (!hasPermissions) { Log.w(TAG, "BluetoothAdapterWrapper.create failed: Lacking Bluetooth permissions."); return null; } BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter == null) { Log.i(TAG, "BluetoothAdapterWrapper.create failed: Default adapter not found."); return null; } else { Log.i(TAG, "BluetoothAdapterWrapper created with default adapter."); return new BluetoothAdapterWrapper(adapter); } }
@Override public Boolean call() { Log.i(TAG, "Trying to extract logcat for minidump"); try { // Step 1: Extract a single logcat file. File logcatFile = getElidedLogcat(); // Step 2: Make copies of logcat file for each minidump then invoke // MinidumpPreparationService on each file pair. int len = mMinidumpFilenames.length; CrashFileManager fileManager = new CrashFileManager(mContext.getCacheDir()); for (int i = 0; i < len; i++) { // Output crash dump file path to logcat so non-browser crashes appear too. Log.i(TAG, "Output crash dump:"); Log.i(TAG, fileManager.getCrashFile(mMinidumpFilenames[i]).getAbsolutePath()); processMinidump(logcatFile, mMinidumpFilenames[i], fileManager, i == len - 1); } return true; } catch (IOException | InterruptedException e) { Log.w(TAG, e.toString()); return false; } }
@Override public boolean onOptionsItemSelected(MenuItem item) { if (item == mDeleteButton) { // Log added for detecting delete button double clicking. Log.i(TAG, "Delete button pressed by user! isFinishing() == " + isFinishing()); mEnhancedBookmarksModel.deleteBookmark(mBookmarkId); finish(); return true; } else if (item.getItemId() == android.R.id.home) { finish(); return true; } return super.onOptionsItemSelected(item); }
/** * Returns true if the Background Sync Manager should be automatically disabled on startup. This * is currently only the case if Play Services is not up to date, since any sync attempts which * fail cannot be reregistered. Better to wait until Play Services is updated before attempting * them. * * @param context The application context. */ @CalledByNative private static boolean shouldDisableBackgroundSync(Context context) { // Check to see if Play Services is up to date, and disable GCM if not. // This will not automatically set {@link sGCMEnabled} to true, in case it has been // disabled in tests. if (sGCMEnabled) { if (!canUseGooglePlayServices(context)) { setGCMEnabled(false); Log.i(TAG, "Disabling Background Sync because Play Services is not up to date."); recordBooleanHistogram("BackgroundSync.LaunchTask.PlayServicesAvailable", false); } else { recordBooleanHistogram("BackgroundSync.LaunchTask.PlayServicesAvailable", true); } } return !sGCMEnabled; }
private void runTest(final String fileName, final String fileNameExpected) throws FileNotFoundException, IOException, InterruptedException, TimeoutException { loadUrlWebViewAsync("file://" + fileName, mTestActivity); if (getInstrumentation().isRebaseline()) { // this is the rebaseline process mTestActivity.waitForFinish(TIMEOUT_SECONDS, TimeUnit.SECONDS); String result = mTestActivity.getTestResult(); writeFile(fileNameExpected, result, true); Log.i(TAG, "file: " + fileNameExpected + " --> rebaselined, length=" + result.length()); } else { String expected = readFile(fileNameExpected); mTestActivity.waitForFinish(TIMEOUT_SECONDS, TimeUnit.SECONDS); String result = mTestActivity.getTestResult(); assertEquals(expected, result); } }
private static ChromiumLinkerParams getLinkerParamsForNewConnection() { if (!sLinkerInitialized) { if (Linker.isUsed()) { sLinkerLoadAddress = Linker.getBaseLoadAddress(); if (sLinkerLoadAddress == 0) { Log.i(TAG, "Shared RELRO support disabled!"); } } sLinkerInitialized = true; } if (sLinkerLoadAddress == 0) return null; // Always wait for the shared RELROs in service processes. final boolean waitForSharedRelros = true; return new ChromiumLinkerParams( sLinkerLoadAddress, waitForSharedRelros, Linker.getTestRunnerClassName()); }
@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); } }
@Override public void onImageAvailable(ImageReader reader) { synchronized (mCaptureStateLock) { if (mCaptureState != CaptureState.STARTED) { Log.e(TAG, "Get captured frame in unexpected state."); return; } } // If device is rotated, inform native, then re-create ImageReader and VirtualDisplay // with the new orientation, and drop the current frame. if (maybeDoRotation()) { createImageReaderWithFormat(); createVirtualDisplay(); return; } try (Image image = reader.acquireLatestImage()) { if (image == null) return; if (reader.getWidth() != image.getWidth() || reader.getHeight() != image.getHeight()) { Log.e( TAG, "ImageReader size (" + reader.getWidth() + "x" + reader.getHeight() + ") did not match Image size (" + image.getWidth() + "x" + image.getHeight() + ")"); throw new IllegalStateException(); } switch (image.getFormat()) { case PixelFormat.RGBA_8888: if (image.getPlanes().length != 1) { Log.e( TAG, "Unexpected image planes for RGBA_8888 format: " + image.getPlanes().length); throw new IllegalStateException(); } nativeOnRGBAFrameAvailable( mNativeScreenCaptureMachineAndroid, image.getPlanes()[0].getBuffer(), image.getPlanes()[0].getRowStride(), image.getCropRect().left, image.getCropRect().top, image.getCropRect().width(), image.getCropRect().height(), image.getTimestamp()); break; case ImageFormat.YUV_420_888: if (image.getPlanes().length != 3) { Log.e( TAG, "Unexpected image planes for YUV_420_888 format: " + image.getPlanes().length); throw new IllegalStateException(); } // The pixel stride of Y plane is always 1. The U/V planes are guaranteed // to have the same row stride and pixel stride. nativeOnI420FrameAvailable( mNativeScreenCaptureMachineAndroid, image.getPlanes()[0].getBuffer(), image.getPlanes()[0].getRowStride(), image.getPlanes()[1].getBuffer(), image.getPlanes()[2].getBuffer(), image.getPlanes()[1].getRowStride(), image.getPlanes()[1].getPixelStride(), image.getCropRect().left, image.getCropRect().top, image.getCropRect().width(), image.getCropRect().height(), image.getTimestamp()); break; default: Log.e(TAG, "Unexpected image format: " + image.getFormat()); throw new IllegalStateException(); } } catch (IllegalStateException ex) { Log.e(TAG, "acquireLatestImage():" + ex); } catch (UnsupportedOperationException ex) { Log.i(TAG, "acquireLatestImage():" + ex); // YUV_420_888 is the preference, but not all devices support it, // fall-back to RGBA_8888 then. mFormat = PixelFormat.RGBA_8888; createImageReaderWithFormat(); createVirtualDisplay(); } }
@Override public void onCreate() { Log.i(TAG, "Creating new ChildProcessService pid=%d", Process.myPid()); if (sContext.get() != null) { throw new RuntimeException("Illegal child process reuse."); } sContext.set(this); super.onCreate(); mMainThread = new Thread( new Runnable() { @Override @SuppressFBWarnings("DM_EXIT") public void run() { try { // CommandLine must be initialized before others, e.g., Linker.isUsed() // may check the command line options. synchronized (mMainThread) { while (mCommandLineParams == null) { mMainThread.wait(); } } CommandLine.init(mCommandLineParams); Linker linker = Linker.getInstance(); boolean useLinker = linker.isUsed(); boolean requestedSharedRelro = false; if (useLinker) { synchronized (mMainThread) { while (!mIsBound) { mMainThread.wait(); } } assert mLinkerParams != null; if (mLinkerParams.mWaitForSharedRelro) { requestedSharedRelro = true; linker.initServiceProcess(mLinkerParams.mBaseLoadAddress); } else { linker.disableSharedRelros(); } linker.setTestRunnerClassName(mLinkerParams.mTestRunnerClassName); } boolean isLoaded = false; if (CommandLine.getInstance() .hasSwitch(BaseSwitches.RENDERER_WAIT_FOR_JAVA_DEBUGGER)) { android.os.Debug.waitForDebugger(); } boolean loadAtFixedAddressFailed = false; try { LibraryLoader.get(LibraryProcessType.PROCESS_CHILD) .loadNow(getApplicationContext()); isLoaded = true; } catch (ProcessInitException e) { if (requestedSharedRelro) { Log.w( TAG, "Failed to load native library with shared RELRO, " + "retrying without"); loadAtFixedAddressFailed = true; } else { Log.e(TAG, "Failed to load native library", e); } } if (!isLoaded && requestedSharedRelro) { linker.disableSharedRelros(); try { LibraryLoader.get(LibraryProcessType.PROCESS_CHILD) .loadNow(getApplicationContext()); isLoaded = true; } catch (ProcessInitException e) { Log.e(TAG, "Failed to load native library on retry", e); } } if (!isLoaded) { System.exit(-1); } LibraryLoader.get(LibraryProcessType.PROCESS_CHILD) .registerRendererProcessHistogram( requestedSharedRelro, loadAtFixedAddressFailed); LibraryLoader.get(LibraryProcessType.PROCESS_CHILD).initialize(); synchronized (mMainThread) { mLibraryInitialized = true; mMainThread.notifyAll(); while (mFdInfos == null) { mMainThread.wait(); } } ContentMain.initApplicationContext(sContext.get().getApplicationContext()); for (FileDescriptorInfo fdInfo : mFdInfos) { nativeRegisterGlobalFileDescriptor( fdInfo.mId, fdInfo.mFd.detachFd(), fdInfo.mOffset, fdInfo.mSize); } nativeInitChildProcess( sContext.get().getApplicationContext(), ChildProcessService.this, mCpuCount, mCpuFeatures); if (mActivitySemaphore.tryAcquire()) { ContentMain.start(); nativeExitChildProcess(); } } catch (InterruptedException e) { Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e); } catch (ProcessInitException e) { Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e); } } }, MAIN_THREAD_NAME); mMainThread.start(); }