OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser; | 5 package org.chromium.chrome.browser; |
6 | 6 |
7 import android.app.Activity; | 7 import android.app.Activity; |
8 import android.app.AlarmManager; | 8 import android.app.AlarmManager; |
9 import android.app.PendingIntent; | 9 import android.app.PendingIntent; |
10 import android.content.Context; | 10 import android.content.Context; |
(...skipping 11 matching lines...) Expand all Loading... |
22 /** | 22 /** |
23 * Handles killing and potentially restarting Chrome's main Browser process. No
te that this class | 23 * Handles killing and potentially restarting Chrome's main Browser process. No
te that this class |
24 * relies on main Chrome activities to properly call {@link Activity#finish()} o
n themselves so that | 24 * relies on main Chrome activities to properly call {@link Activity#finish()} o
n themselves so that |
25 * it will be notified that all {@link Activity}s under this {@link Application}
have been | 25 * it will be notified that all {@link Activity}s under this {@link Application}
have been |
26 * destroyed. | 26 * destroyed. |
27 */ | 27 */ |
28 class ChromeLifetimeController implements ApplicationLifetime.Observer, | 28 class ChromeLifetimeController implements ApplicationLifetime.Observer, |
29 ApplicationStatus.ActivityStateListener { | 29 ApplicationStatus.ActivityStateListener { |
30 private static final String TAG = "ChromeLifetimeController"; | 30 private static final String TAG = "ChromeLifetimeController"; |
31 | 31 |
| 32 // The amount of time to wait for Chrome to destroy all the activities. |
| 33 private static final long WATCHDOG_DELAY = 1000; |
| 34 |
32 private final Context mContext; | 35 private final Context mContext; |
33 private boolean mRestartChromeOnDestroy; | 36 private boolean mRestartChromeOnDestroy; |
34 private int mRemainingActivitiesCount = 0; | 37 private int mRemainingActivitiesCount = 0; |
| 38 private final Handler mHandler; |
35 | 39 |
36 /** | 40 /** |
37 * Creates a {@link ChromeLifetimeController} instance. | 41 * Creates a {@link ChromeLifetimeController} instance. |
38 * @param context A {@link Context} instance. The application context will
be saved from this | 42 * @param context A {@link Context} instance. The application context will
be saved from this |
39 * one. | 43 * one. |
40 */ | 44 */ |
41 public ChromeLifetimeController(Context context) { | 45 public ChromeLifetimeController(Context context) { |
42 mContext = context.getApplicationContext(); | 46 mContext = context.getApplicationContext(); |
43 ApplicationLifetime.addObserver(this); | 47 ApplicationLifetime.addObserver(this); |
| 48 mHandler = new Handler(Looper.getMainLooper()); |
44 } | 49 } |
45 | 50 |
46 @Override | 51 @Override |
47 public void onTerminate(boolean restart) { | 52 public void onTerminate(boolean restart) { |
48 mRestartChromeOnDestroy = restart; | 53 mRestartChromeOnDestroy = restart; |
49 | 54 |
50 // We've called terminate twice, just wait for the first call to take ef
fect. | 55 // We've called terminate twice, just wait for the first call to take ef
fect. |
51 if (mRemainingActivitiesCount > 0) { | 56 if (mRemainingActivitiesCount > 0) { |
52 Log.w(TAG, "onTerminate called twice"); | 57 Log.w(TAG, "onTerminate called twice"); |
53 return; | 58 return; |
54 } | 59 } |
55 | 60 |
56 for (WeakReference<Activity> weakActivity : ApplicationStatus.getRunning
Activities()) { | 61 for (WeakReference<Activity> weakActivity : ApplicationStatus.getRunning
Activities()) { |
57 Activity activity = weakActivity.get(); | 62 Activity activity = weakActivity.get(); |
58 if (activity != null) { | 63 if (activity != null) { |
59 ApplicationStatus.registerStateListenerForActivity(this, activit
y); | 64 ApplicationStatus.registerStateListenerForActivity(this, activit
y); |
60 mRemainingActivitiesCount++; | 65 mRemainingActivitiesCount++; |
61 activity.finish(); | 66 activity.finish(); |
62 } | 67 } |
63 } | 68 } |
| 69 |
| 70 // Post a watchdog -- if Android is taking a long time to call onDestroy
, kill the process. |
| 71 mHandler.postDelayed(new Runnable() { |
| 72 @Override |
| 73 public void run() { |
| 74 if (mRemainingActivitiesCount > 0) { |
| 75 destroyProcess(); |
| 76 } |
| 77 } |
| 78 }, WATCHDOG_DELAY); |
64 } | 79 } |
65 | 80 |
66 | 81 |
67 @Override | 82 @Override |
68 public void onActivityStateChange(Activity activity, int newState) { | 83 public void onActivityStateChange(Activity activity, int newState) { |
69 assert mRemainingActivitiesCount > 0; | 84 assert mRemainingActivitiesCount > 0; |
70 if (newState == ActivityState.DESTROYED) { | 85 if (newState == ActivityState.DESTROYED) { |
71 mRemainingActivitiesCount--; | 86 mRemainingActivitiesCount--; |
72 if (mRemainingActivitiesCount == 0) { | 87 if (mRemainingActivitiesCount == 0) { |
73 destroyProcess(); | 88 destroyProcess(); |
74 } | 89 } |
75 } | 90 } |
76 | 91 |
77 } | 92 } |
78 | 93 |
79 private void destroyProcess() { | 94 private void destroyProcess() { |
80 Handler handler = new Handler(Looper.getMainLooper()); | 95 mHandler.post(new Runnable() { |
81 handler.post(new Runnable() { | |
82 @Override | 96 @Override |
83 public void run() { | 97 public void run() { |
84 if (mRestartChromeOnDestroy) scheduleRestart(mContext); | 98 if (mRestartChromeOnDestroy) scheduleRestart(mContext); |
85 | 99 |
86 Log.w(TAG, "Forcefully killing process..."); | 100 Log.w(TAG, "Forcefully killing process..."); |
87 Process.killProcess(Process.myPid()); | 101 Process.killProcess(Process.myPid()); |
88 | 102 |
89 mRestartChromeOnDestroy = false; | 103 mRestartChromeOnDestroy = false; |
90 } | 104 } |
91 }); | 105 }); |
92 } | 106 } |
93 | 107 |
94 private static void scheduleRestart(Context context) { | 108 private static void scheduleRestart(Context context) { |
95 Intent intent = new Intent(); | 109 Intent intent = new Intent(); |
96 intent.setPackage(context.getPackageName()); | 110 intent.setPackage(context.getPackageName()); |
97 intent.setAction(Intent.ACTION_MAIN); | 111 intent.setAction(Intent.ACTION_MAIN); |
98 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | 112 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
99 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, inte
nt, | 113 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, inte
nt, |
100 PendingIntent.FLAG_ONE_SHOT); | 114 PendingIntent.FLAG_ONE_SHOT); |
101 if (pendingIntent != null) { | 115 if (pendingIntent != null) { |
102 AlarmManager am = (AlarmManager) context.getSystemService(Context.AL
ARM_SERVICE); | 116 AlarmManager am = (AlarmManager) context.getSystemService(Context.AL
ARM_SERVICE); |
103 am.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pendingI
ntent); | 117 am.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pendingI
ntent); |
104 } | 118 } |
105 } | 119 } |
106 } | 120 } |
OLD | NEW |