Remove BG service from calendar provider.
The purpose of EmptyService was to keep the process running until
it sends a broadcast with a delay which is scheduled with a handler...
However "sending a broadcast with a delay" can just be done
Bug 35350114
Test: Manual tests with the verbose log enabled.
- adb shell setprop log.tag.CalendarProvider2 VERBOSE &&
adb shell am force-stop com.android.providers.calendar
- Then create/delete events on the calendar app and monitor
adb logcat | grep 'sendUpdateNotification'
- Then check the alarm and make sure PROVIDER_CHANGED is scheduled
at the right time.
adb shell dumpsys alarm | grep -A 4 -P 'ELAPSED.*com.android.providers.calendar'
Change-Id: Id2c0e10604bb7fdd3e9f8650295da83b3a62ecff
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1d88eb9..255f39a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -54,13 +54,6 @@
android:readPermission="android.permission.READ_CALENDAR"
android:writePermission="android.permission.WRITE_CALENDAR" />
- <!-- This is used to keep the provider alive long enough to send update
- intent broadcasts. -->
- <service android:name=".EmptyService" />
- <!-- This is used to keep the provider alive long enough to clean up scheduled
- alarms after boot. -->
- <service android:name=".CalendarReceiver$RemoveScheduledAlarmsEmptyService" />
-
<activity android:name="CalendarContentProviderTests" android:label="Calendar Content Provider"
android:exported="false">
<intent-filter>
diff --git a/src/com/android/providers/calendar/CalendarAlarmManager.java b/src/com/android/providers/calendar/CalendarAlarmManager.java
index adb98c4..b107bf7 100644
--- a/src/com/android/providers/calendar/CalendarAlarmManager.java
+++ b/src/com/android/providers/calendar/CalendarAlarmManager.java
@@ -499,6 +499,10 @@
+ CalendarAlerts.STATE_SCHEDULED, null /* whereArgs */);
}
+ public void set(int type, long triggerAtTime, PendingIntent operation) {
+ mAlarmManager.set(type, triggerAtTime, operation);
+ }
+
public void setExact(int type, long triggerAtTime, PendingIntent operation) {
mAlarmManager.setExact(type, triggerAtTime, operation);
}
diff --git a/src/com/android/providers/calendar/CalendarProvider2.java b/src/com/android/providers/calendar/CalendarProvider2.java
index a85c45b..08fe756 100644
--- a/src/com/android/providers/calendar/CalendarProvider2.java
+++ b/src/com/android/providers/calendar/CalendarProvider2.java
@@ -20,7 +20,9 @@
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.OnAccountsUpdateListener;
+import android.app.AlarmManager;
import android.app.AppOpsManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -40,6 +42,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.Process;
+import android.os.SystemClock;
import android.provider.BaseColumns;
import android.provider.CalendarContract;
import android.provider.CalendarContract.Attendees;
@@ -446,23 +449,6 @@
@VisibleForTesting
protected CalendarAlarmManager mCalendarAlarm;
- private final Handler mBroadcastHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- Context context = CalendarProvider2.this.mContext;
- if (msg.what == UPDATE_BROADCAST_MSG) {
- // Broadcast a provider changed intent
- doSendUpdateNotification();
- // Because the handler does not guarantee message delivery in
- // the case that the provider is killed, we need to make sure
- // that the provider stays alive long enough to deliver the
- // notification. This empty service is sufficient to "wedge" the
- // process until we stop it here.
- context.stopService(new Intent(context, EmptyService.class));
- }
- }
- };
-
/**
* Listens for timezone changes and disk-no-longer-full events
*/
@@ -4537,11 +4523,9 @@
}
/**
- * Call this to trigger a broadcast of the ACTION_PROVIDER_CHANGED intent.
+ * Call this to trigger a broadcast of the ACTION_PROVIDER_CHANGED intent with a delay.
* This also provides a timeout, so any calls to this method will be batched
- * over a period of BROADCAST_TIMEOUT_MILLIS defined in this class. The
- * actual sending of the intent is done in
- * {@link #doSendUpdateNotification()}.
+ * over a period of BROADCAST_TIMEOUT_MILLIS defined in this class.
*
* TODO add support for eventId
*
@@ -4550,47 +4534,24 @@
*/
private void sendUpdateNotification(long eventId,
boolean callerIsSyncAdapter) {
- // Are there any pending broadcast requests?
- if (mBroadcastHandler.hasMessages(UPDATE_BROADCAST_MSG)) {
- // Delete any pending requests, before requeuing a fresh one
- mBroadcastHandler.removeMessages(UPDATE_BROADCAST_MSG);
- } else {
- // Because the handler does not guarantee message delivery in
- // the case that the provider is killed, we need to make sure
- // that the provider stays alive long enough to deliver the
- // notification. This empty service is sufficient to "wedge" the
- // process until we stop it here.
- mContext.startService(new Intent(mContext, EmptyService.class));
- }
// We use a much longer delay for sync-related updates, to prevent any
// receivers from slowing down the sync
- long delay = callerIsSyncAdapter ?
+ final long delay = callerIsSyncAdapter ?
SYNC_UPDATE_BROADCAST_TIMEOUT_MILLIS :
UPDATE_BROADCAST_TIMEOUT_MILLIS;
- // Despite the fact that we actually only ever use one message at a time
- // for now, it is really important to call obtainMessage() to get a
- // clean instance. This avoids potentially infinite loops resulting
- // adding the same instance to the message queue twice, since the
- // message queue implements its linked list using a field from Message.
- Message msg = mBroadcastHandler.obtainMessage(UPDATE_BROADCAST_MSG);
- mBroadcastHandler.sendMessageDelayed(msg, delay);
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "sendUpdateNotification: delay=" + delay);
+ }
+
+ mCalendarAlarm.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + delay,
+ PendingIntent.getBroadcast(mContext, 0, createProviderChangedBroadcast(),
+ PendingIntent.FLAG_UPDATE_CURRENT));
}
- /**
- * This method should not ever be called directly, to prevent sending too
- * many potentially expensive broadcasts. Instead, call
- * {@link #sendUpdateNotification(boolean)} instead.
- *
- * @see #sendUpdateNotification(boolean)
- */
- private void doSendUpdateNotification() {
- Intent intent = new Intent(Intent.ACTION_PROVIDER_CHANGED,
- CalendarContract.CONTENT_URI);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- if (Log.isLoggable(TAG, Log.INFO)) {
- Log.i(TAG, "Sending notification intent: " + intent);
- }
- mContext.sendBroadcast(intent, null);
+ private Intent createProviderChangedBroadcast() {
+ return new Intent(Intent.ACTION_PROVIDER_CHANGED, CalendarContract.CONTENT_URI)
+ .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
}
private static final int TRANSACTION_QUERY = 0;
diff --git a/src/com/android/providers/calendar/EmptyService.java b/src/com/android/providers/calendar/EmptyService.java
deleted file mode 100644
index 70cf3d4..0000000
--- a/src/com/android/providers/calendar/EmptyService.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.android.providers.calendar;
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-/**
- * Background {@link Service} that is used to keep our process alive long enough
- * for background threads to finish. Started and stopped directly by specific
- * background tasks when needed.
- */
-public class EmptyService extends Service {
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-}
diff --git a/tests/src/com/android/providers/calendar/CalendarProvider2ForTesting.java b/tests/src/com/android/providers/calendar/CalendarProvider2ForTesting.java
index e54f5bd..f73168e 100644
--- a/tests/src/com/android/providers/calendar/CalendarProvider2ForTesting.java
+++ b/tests/src/com/android/providers/calendar/CalendarProvider2ForTesting.java
@@ -58,6 +58,10 @@
}
@Override
+ public void set(int type, long triggerAtTime, PendingIntent operation) {
+ }
+
+ @Override
public void setExact(int type, long triggerAtTime, PendingIntent operation) {
}