Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/precache/PrecacheService.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/precache/PrecacheService.java b/chrome/android/java/src/org/chromium/chrome/browser/precache/PrecacheService.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..025f50bbeba39346705f194c6bd9771b665b9d9b |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/precache/PrecacheService.java |
| @@ -0,0 +1,211 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
|
Yaron
2015/03/25 15:16:12
We've been updating copyright dates in the moves t
sadrul
2015/03/25 18:05:25
Done.
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.chrome.browser.precache; |
| + |
| +import android.app.Service; |
| +import android.content.BroadcastReceiver; |
| +import android.content.Context; |
| +import android.content.Intent; |
| +import android.content.IntentFilter; |
| +import android.net.ConnectivityManager; |
| +import android.os.IBinder; |
| +import android.os.PowerManager; |
| +import android.os.PowerManager.WakeLock; |
| +import android.util.Log; |
| + |
| +import org.chromium.base.VisibleForTesting; |
| +import org.chromium.base.annotations.SuppressFBWarnings; |
| +import org.chromium.base.library_loader.LibraryProcessType; |
| +import org.chromium.base.library_loader.ProcessInitException; |
| +import org.chromium.components.precache.DeviceState; |
| +import org.chromium.content.browser.BrowserStartupController; |
| + |
| +/** |
| + * Background service that runs while Chrome is precaching resources. Precaching is only done while |
| + * the device is connected to power, Wi-Fi, and the device is not interactive (e.g., the screen is |
| + * off. This is a sticky service that is started when the {@link PrecacheServiceLauncher} |
| + * determines that conditions are right for precaching. Once started, this service runs until |
| + * either precaching finishes successfully, or the conditions are no longer met. |
| + */ |
| +public class PrecacheService extends Service { |
| + private static final String TAG = "PrecacheService"; |
| + |
| + public static final String ACTION_START_PRECACHE = |
| + "org.chromium.components.precache.PrecacheService.START_PRECACHE"; |
|
Yaron
2015/03/25 15:16:12
Why is this using the component's precache package
sadrul
2015/03/25 18:05:25
Oops, my bad, overzealous search/replace! (I had i
|
| + |
| + /** Wakelock that is held while precaching is in progress. */ |
| + private WakeLock mPrecachingWakeLock; |
| + |
| + /** True if there is a precache in progress. */ |
| + private boolean mIsPrecaching = false; |
| + |
| + @VisibleForTesting |
| + boolean isPrecaching() { |
| + return mIsPrecaching; |
| + } |
| + |
| + private DeviceState mDeviceState = DeviceState.getInstance(); |
| + |
| + @VisibleForTesting |
| + void setDeviceState(DeviceState deviceState) { |
| + mDeviceState = deviceState; |
| + } |
| + |
| + |
| + /** Receiver that will be notified when conditions become wrong for precaching. */ |
| + private final BroadcastReceiver mDeviceStateReceiver = new BroadcastReceiver() { |
| + @Override |
| + public void onReceive(Context context, Intent intent) { |
| + if (mIsPrecaching && (mDeviceState.isInteractive(context) |
| + || !mDeviceState.isPowerConnected(context) |
| + || !mDeviceState.isWifiAvailable(context))) { |
| + cancelPrecaching(); |
| + } |
| + } |
| + }; |
| + |
| + @VisibleForTesting |
| + BroadcastReceiver getDeviceStateReceiver() { |
| + return mDeviceStateReceiver; |
| + } |
| + |
| + @VisibleForTesting |
| + void handlePrecacheCompleted() { |
| + if (mIsPrecaching) finishPrecaching(); |
| + } |
| + |
| + /** PrecacheLauncher used to run precaching. */ |
| + private PrecacheLauncher mPrecacheLauncher = new PrecacheLauncher() { |
| + @Override |
| + protected void onPrecacheCompleted() { |
| + handlePrecacheCompleted(); |
| + } |
| + }; |
| + |
| + @VisibleForTesting |
| + void setPrecacheLauncher(PrecacheLauncher precacheLauncher) { |
| + mPrecacheLauncher = precacheLauncher; |
| + } |
| + |
| + @Override |
| + public void onCreate() { |
| + super.onCreate(); |
| + registerDeviceStateReceiver(); |
| + } |
| + |
| + @Override |
| + public void onDestroy() { |
| + if (mIsPrecaching) cancelPrecaching(); |
| + |
| + unregisterReceiver(mDeviceStateReceiver); |
| + mPrecacheLauncher.destroy(); |
| + releasePrecachingWakeLock(); |
| + |
| + super.onDestroy(); |
| + } |
| + |
| + @Override |
| + public int onStartCommand(Intent intent, int flags, int startId) { |
| + try { |
| + if (intent != null && ACTION_START_PRECACHE.equals(intent.getAction()) |
| + && !mIsPrecaching) { |
| + // Only start precaching if precaching is not already in progress. |
| + startPrecaching(); |
| + } |
| + } finally { |
| + PrecacheServiceLauncher.releaseWakeLock(); |
| + } |
| + // The PrecacheService should only be running while precaching is in progress. Return |
| + // {@link Service.START_STICKY} if precaching is in progress to keep the service running; |
| + // otherwise, return {@link Service.START_NOT_STICKY} to cause the service to stop once it |
| + // is done processing commands sent to it. |
| + return mIsPrecaching ? START_STICKY : START_NOT_STICKY; |
| + } |
| + |
| + /** PrecacheService does not support binding. */ |
| + @Override |
| + public IBinder onBind(Intent intent) { |
| + return null; |
| + } |
| + |
| + /** Attempt to start up the browser processes and load the native libraries. */ |
| + @SuppressFBWarnings("DM_EXIT") |
| + @VisibleForTesting |
| + void prepareNativeLibraries() { |
| + try { |
| + BrowserStartupController.get(getApplicationContext(), |
| + LibraryProcessType.PROCESS_BROWSER) |
| + .startBrowserProcessesSync(false); |
| + } catch (ProcessInitException e) { |
| + Log.e(TAG, "ProcessInitException while starting the browser process"); |
| + // Since the library failed to initialize nothing in the application |
| + // can work, so kill the whole application not just the activity. |
| + System.exit(-1); |
| + } |
| + } |
| + |
| + /** Begin a precache cycle. */ |
| + private void startPrecaching() { |
| + Log.v(TAG, "Start precaching"); |
| + prepareNativeLibraries(); |
| + mIsPrecaching = true; |
| + acquirePrecachingWakeLock(); |
| + |
| + // In certain cases, the PrecacheLauncher will skip precaching entirely and call |
| + // finishPrecaching() before this call to mPrecacheLauncher.start() returns, so the call to |
| + // mPrecacheLauncher.start() must happen after acquiring the wake lock to ensure that the |
| + // wake lock is released properly. |
| + mPrecacheLauncher.start(); |
| + } |
| + |
| + /** End a precache cycle. */ |
| + private void finishPrecaching() { |
| + Log.v(TAG, "Finish precaching"); |
| + shutdownPrecaching(); |
| + } |
| + |
| + /** Cancel a precache cycle. */ |
| + private void cancelPrecaching() { |
| + Log.v(TAG, "Cancel precaching"); |
| + prepareNativeLibraries(); |
| + mPrecacheLauncher.cancel(); |
| + |
| + shutdownPrecaching(); |
| + } |
| + |
| + /** |
| + * Update state to indicate that precaching is no longer in progress, and stop the service. |
| + */ |
| + private void shutdownPrecaching() { |
| + mIsPrecaching = false; |
| + releasePrecachingWakeLock(); |
| + stopSelf(); |
| + } |
| + |
| + /** Register a BroadcastReceiver to detect when conditions become wrong for precaching. */ |
| + private void registerDeviceStateReceiver() { |
| + IntentFilter filter = new IntentFilter(); |
| + filter.addAction(Intent.ACTION_POWER_DISCONNECTED); |
| + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); |
| + filter.addAction(Intent.ACTION_SCREEN_ON); |
| + registerReceiver(mDeviceStateReceiver, filter); |
| + } |
| + |
| + /** Acquire the precaching WakeLock. */ |
| + private void acquirePrecachingWakeLock() { |
| + if (mPrecachingWakeLock == null) { |
| + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); |
| + mPrecachingWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); |
| + } |
| + mPrecachingWakeLock.acquire(); |
| + } |
| + |
| + /** Release the precaching WakeLock if it is held. */ |
| + private void releasePrecachingWakeLock() { |
| + if (mPrecachingWakeLock != null && mPrecachingWakeLock.isHeld()) { |
| + mPrecachingWakeLock.release(); |
| + } |
| + } |
| +} |