Android 6 (API23) introduced Doze mode which interferes with AlarmManager. It uses certain maintenance windows to handle alarms, so even if you used setExactAndAllowWhileIdle()
you cannot make sure that your alarm fires at the desired point of time.
You can turn this behavior off for your app using your phone's settings (Settings/General/Battery & power saving/Battery usage/Ignore optimizations
or similar)
Inside your app you can check this setting ...
String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm.isIgnoringBatteryOptimizations(packageName)) {
// your app is ignoring Doze battery optimization
}
... and eventually show the respective settings dialog:
Intent intent = new Intent();
String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);