4

I create a PendingIntent like this:

Intent intent = new Intent(context, AlarmReceiver.class);
intent.setAction("Foobar");
intent.putExtra(EXTRA_ALARM, alarm);
intent.putExtra(EXTRA_TRYTWO, tryTwo);
intent.putExtra(EXTRA_BEGAN_TIME, beganTime);

return PendingIntent.getBroadcast(
        context, (int) alarm.getId(), intent, PendingIntent.FLAG_UPDATE_CURRENT
);

The alarm variable is a Parcelable. I schedule the PendingIntent like this:

PendingIntent alarmModifyPendingIntent = PendingIntent.getActivity(
        context, 0, editIntent, PendingIntent.FLAG_CANCEL_CURRENT
);

am.setAlarmClock(
    new AlarmManager.AlarmClockInfo(time, alarmModifyPendingIntent), pendingIntent
);

Where the variable pendingIntent is created as shown above.

The AlarmReceiver object receives an Intent in onReceive at the correct time. However, this Intent does not contain the extras that I have set. For instance intent.getParcelableExtra(EXTRA_ALARM) returns null.

This problem occurs with Android 7.0 (API level 24) at least, using an LG G5.

Using FLAG_CANCEL_CURRENT or FLAG_ONE_SHOT does not work either.

Matthew Mitchell
  • 5,293
  • 14
  • 70
  • 122

1 Answers1

9

The alarm variable is a Parcelable.

It is not safe to put a custom Parcelable in an Intent that is delivered to another process. This is particularly true with AlarmManager on Android 7.0.

You need to replace that Parcelable with something else, such as a byte[], where you manually convert your Parcelable to/from that byte[].

Community
  • 1
  • 1
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thank you for bringing this to my attention. I shall investigate. – Matthew Mitchell Dec 13 '16 at 22:53
  • I just tested it and you were indeed correct! Converting to byte[] works. Many thanks. – Matthew Mitchell Dec 13 '16 at 23:10
  • Online parcelable converters if used will no longer work if and until they convert the parcel to byte[]. – Lalith B Dec 13 '16 at 23:17
  • @MatthewMitchell: Any time another process would need one of your classes, you'll have the issue. – CommonsWare Dec 13 '16 at 23:28
  • Shouldn't it be considered a bug? Does Google warn about this anywhere? Does it have a support library class for helping handling this case? Does the Parcelable issue exist in other cases, other than AlarmManager ? – android developer Apr 09 '17 at 14:32
  • @androiddeveloper: "Shouldn't it be considered a bug?" -- no, IMHO. "Does Google warn about this anywhere?" -- not that I am aware of, outside of the comments on [the N issue I mentioned in my blog post](https://code.google.com/p/android/issues/detail?id=209422). "Does it have a support library class for helping handling this case?" -- no. "Does the Parcelable issue exist in other cases, other than AlarmManager ?" -- any time you pass a custom `Parcelable` outside of your process, the risk of this problem exists. – CommonsWare Apr 09 '17 at 14:44
  • @CommonsWare Can you provide example/s for passing a custom Parcelable outside of your process? Why don't you consider this a bug? It worked in previous versions, and it's quite a basic thing to be able to do... – android developer Apr 10 '17 at 21:14
  • @androiddeveloper: "Can you provide example/s for passing a custom Parcelable outside of your process?" -- convert them to/from `byte[]`. See [this sample app](https://github.com/commonsguy/cw-omnibus/tree/master/Parcelable/Marshall). "Why don't you consider this a bug?" -- because any time you pass a custom `Parcelable` outside of your app, another app might try to read it in, and that's going to fail, because the other app does not have your class. In this case, the problem stems from `fillIn()` on `PendingIntent` IIRC. I try to stick to built-in types. – CommonsWare Apr 10 '17 at 21:19
  • @CommonsWare I didn't mean provide a code. I mean to describe another case this occurs, other than AlarmManager. About the issue itself, according to this: https://code.google.com/p/android/issues/detail?id=209422#c3 , they say it will get updated in the docs, but I don't see the docs saying about this matter, and the issue is already closed... – android developer Apr 10 '17 at 23:44
  • @androiddeveloper: "I mean to describe another case this occurs, other than AlarmManager" -- any time you use a custom `Parcelable` in a `PendingIntent` that is filled in by another app. I seem to recall this happening with notifications. I would expect it to happen with the `PendingIntent` flavors of `LocationManager` methods. And so on. What changed is that `AlarmManager` never used to fill in a `PendingIntent`, and now it does. – CommonsWare Apr 10 '17 at 23:52
  • @CommonsWare So is it at least safe to put byte array and primitive Java data there? Just not Parcealable ? What about Parcealable objects that are a part of Android framework (you wrote "custom" ones) ? – android developer Apr 11 '17 at 08:12
  • 1
    @androiddeveloper: What is causing the crash is that another process is trying to work with the extras in an `Intent`, and one of those is from a custom `Parcelable` class that the other process does not have. `Parcelable` classes that are in the zygote (i.e., classes in the framework, not from a library) are safe, as all Android SDK processes have the same definitions of those classes. Primitive data is also safe. However, `Serializable` will have the same problem as `Parcelable`, for the same reasons. – CommonsWare Apr 11 '17 at 11:32
  • @CommonsWare So the conclusion is to never put any Parcelable object into Pending intents, and only the primitive data are safe to use, right? Thanks. – android developer Apr 11 '17 at 11:59
  • @androiddeveloper: Primitive data, platform-supplied `Parcelable`, platform-supplied `Serializable`, and arrays/lists of those should all be fine. If you need a custom `Parcelable` or `Serializable` subclass, the safest thing is to convert it to/from a `byte[]` yourself. – CommonsWare Apr 11 '17 at 12:17
  • @CommonsWare What kind of platform-supplied Parcelable/Serializable ? Like PackageInfo for example? This will be safe to send there? – android developer Apr 11 '17 at 16:45
  • @androiddeveloper: Sure. That is defined in the framework. Each Android SDK process has that class, and the same definition of that class to boot. `Bundle`, `Uri`, and lots of other `Parcelable` and `Serializable` classes will be safe. What is *not* safe is a *custom* one, where your app has the class, but apps (or system processes) that might work with your extras do not. – CommonsWare Apr 11 '17 at 17:05
  • @CommonsWare Thank you. I find this quite weird though. They could just pass it forward as normal intents with extras. No reason to mess with its content. – android developer Apr 11 '17 at 17:32
  • @CommonsWare Thank you. – Piyush Malaviya Nov 17 '17 at 13:10