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(); |
+ } |
+ } |
+} |