Действие уведомления iOS 8: "Ошибка доступа к объекту при попытке блокировки связки ключей" при доступе к цепочке ключей в "doneFinishLaunchingWithOptions"
Я наблюдаю за ошибкой keychain в консоли устройства, которую выбрал SecItemCopyMatching
при действии на push-уведомление iOS 8 на заблокированном телефоне. Подробные шаги воспроизведения следующие:
- Удалите все предыдущие версии приложения. Создайте версию приложения Appstore на устройстве. Сила покидает приложение.
- Увеличить номер сборки и создать новую версию на устройстве. Это имитирует поток обновления приложения. Force quit the app (В реальной жизни приложение может быть убито ОС из-за давления памяти. Силовое прекращение имитирует это поведение).
- Отправить push-уведомление для приложения, когда телефон заблокирован.
- При заблокированном телефоне проведите пальцем влево, чтобы увидеть кнопки действий, и нажмите одну из кнопок действий.
- Приложение проснулось,
didFinishLaunchingWithOptions
получает вызов, который пытается получить доступ к элементу keychain. При запуске SecItemCopyMatching
в консоли устройства появляется сообщение об ошибке Access to item attempted while keychain is locked
.
Полный журнал ошибок показан ниже. В последней строке отображается конкретное сообщение об ошибке приложения.
ReportCrash[32481] <Error>: task_set_exception_ports(B07, 400, D03, 0, 0) failed with error (4: (os/kern) invalid argument)
ReportCrash[32481] <Notice>: ReportCrash acting against PID 31423
diagnosticd[32258] <Error>: error evaluating process info - pid: 31423, punique: 131317
ReportCrash[32481] <Notice>: Formulating crash report for process cfprefsd[31423]
com.apple.xpc.launchd[1] (com.apple.cfprefsd.xpc.daemon[31423]) <Notice>: Service exited due to signal: Bus error: 10
My App[32480] <Error>: assertion failed: 12F70: libxpc.dylib + 71768 [B870B51D-AA85-3686-A7D9-ACD48C5FE153]: 0x7d
Unknown[32480] <Error>:
ReportCrash[32481] <Notice>: Saved report to /Library/Logs/CrashReporter/cfprefsd_2015-07-02-150139_Xianjing-Hus-iPhone.ips
securityd[32279] <Error>: s3dl_query_row decode genp,rowid=8099 failed (-25308): The operation couldn’t be completed. (OSStatus error -25308 - ks_crypt: e00002e2 failed to unwrap item (class 6, bag: 0) Access to item attempted while keychain is locked.)
securityd[32279] <Error>: securityd_xpc_dictionary_handler Okta Verify[32480] copy_matching The operation couldn’t be completed. (OSStatus error -25308 - ks_crypt: e00002e2 failed to unwrap item (class 6, bag: 0) Access to item attempted while keychain is locked.)
My App[32480] <Error>: SecOSStatusWith error:[-25308] The operation couldn’t be completed. (OSStatus error -25308 - Remote error : The operation couldn't be completed. (OSStatus error -25308 - ks_crypt: e00002e2 failed to unwrap item (class 6, bag: 0) Access to item attempted while keychain is locked.))
Несколько вещей:
- Доступность элемента keychain устанавливается на
kSecAttrAccessibleAlways
.
- Как видно из вышеприведенного журнала устройств, перед проблемой всегда происходит сбой процесса
cfprefsd
.
- Эта проблема возникает только в сборках Appstore, а не в сборках отладки.
- Эта проблема возникает только при попытке выполнить уведомление о заблокированном телефоне.
- Эта проблема возникает только в том случае, когда приложение обновляется, как описано в вышеописанных этажах.
- Поскольку я принудительно завершаю приложение, когда появляется push-уведомление, и я нажал кнопку действия, мое приложение будет запущено в фоновом режиме.
didFinishLaunchingWithOptions
вызывается, и внутри этого метода делегата я делаю свой доступ к keychain, который выдает ошибку.
Кто-нибудь видел подобную ошибку, и если да, то как вы решили проблему? Любая помощь приветствуется.
Обновление: прикрепление cfprefsd
журнала сбоев
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Subtype: unknown at 0x00000001007d4000
Triggered by Thread: 2
Thread 0 name: Dispatch queue: com.apple.libdispatch-manager
Thread 0:
0 libsystem_kernel.dylib 0x0000000197d88c24 kevent64 + 8
1 libdispatch.dylib 0x0000000197c6de6c _dispatch_mgr_invoke + 272
2 libdispatch.dylib 0x0000000197c5f998 _dispatch_mgr_thread + 48
Thread 1 name: Dispatch queue: com.apple.root.default-qos.overcommit
Thread 1:
0 libsystem_kernel.dylib 0x0000000197da3984 __sigsuspend_nocancel + 8
1 libdispatch.dylib 0x0000000197c6921c _dispatch_sigsuspend + 24
2 libdispatch.dylib 0x0000000197c69200 _dispatch_sig_thread + 44
Thread 2 name: Dispatch queue: src
Thread 2 Crashed:
0 libsystem_platform.dylib 0x0000000197e35300 _platform_memmove + 176
1 libxpc.dylib 0x0000000197e6567c xpc_data_create + 84
2 CoreFoundation 0x0000000185d5a9b8 -[CFPDSource acceptMessage:] + 1956
3 CoreFoundation 0x0000000185dc0da8 __handle_synchronize_message_block_invoke103 + 172
4 CoreFoundation 0x0000000185d57c58 __88+[CFPDSource withSourceForDomain:inContainer:user:byHost:managed:synchronously:perform:]_block_invoke_2 + 24
5 CoreFoundation 0x0000000185d5955c __25-[CFPDSource lockedSync:]_block_invoke + 44
6 libdispatch.dylib 0x0000000197c5d950 _dispatch_client_callout + 12
7 libdispatch.dylib 0x0000000197c671e0 _dispatch_barrier_sync_f_invoke + 72
8 CoreFoundation 0x0000000185d59520 -[CFPDSource lockedSync:] + 80
9 CoreFoundation 0x0000000185d57c0c __88+[CFPDSource withSourceForDomain:inContainer:user:byHost:managed:synchronously:perform:]_block_invoke + 504
10 libdispatch.dylib 0x0000000197c5d950 _dispatch_client_callout + 12
11 libdispatch.dylib 0x0000000197c671e0 _dispatch_barrier_sync_f_invoke + 72
12 CoreFoundation 0x0000000185d576fc +[CFPDSource withSourceForDomain:inContainer:user:byHost:managed:synchronously:perform:] + 364
13 CoreFoundation 0x0000000185dc0508 handle_message + 1312
14 CoreFoundation 0x0000000185dc081c __handle_multi_message_block_invoke_2 + 124
15 libxpc.dylib 0x0000000197e657c0 xpc_array_apply + 76
16 CoreFoundation 0x0000000185dc05f8 handle_message + 1552
17 CoreFoundation 0x0000000185dbffd4 ____CFXPreferencesDaemon_main_block_invoke_5 + 132
18 libxpc.dylib 0x0000000197e64cc8 _xpc_connection_call_event_handler + 64
19 libxpc.dylib 0x0000000197e62bcc _xpc_connection_mach_event + 2156
20 libdispatch.dylib 0x0000000197c5da24 _dispatch_client_callout4 + 12
21 libdispatch.dylib 0x0000000197c6113c _dispatch_mach_msg_invoke + 488
22 libdispatch.dylib 0x0000000197c682d0 _dispatch_queue_drain + 2004
23 libdispatch.dylib 0x0000000197c60664 _dispatch_mach_invoke + 132
24 libdispatch.dylib 0x0000000197c6a314 _dispatch_root_queue_drain + 716
25 libdispatch.dylib 0x0000000197c6bc48 _dispatch_worker_thread3 + 104
26 libsystem_pthread.dylib 0x0000000197e3d228 _pthread_wqthread + 812
27 libsystem_pthread.dylib 0x0000000197e3ceec start_wqthread + 0
Ответы
Ответ 1
Эта ошибка, безусловно, вызвана попыткой доступа к элементу kSecAttrAccessibleWhenUnlocked
, пока устройство все еще заблокировано. Вы можете сказать это, просто просмотрев следующую строку журнала, который вы предоставили:
securityd[32279] <Error>: securityd_xpc_dictionary_handler Okta Verify[32480] copy_matching The operation couldn’t be completed. (OSStatus error -25308 - ks_crypt: e00002e2 failed to unwrap item (class 6, bag: 0) Access to item attempted while keychain is locked.)
Класс 6 - kSecAttrAccessibleWhenUnlocked
(и kSecAttrAccessibleAlways
- класс 8) - см. слайд 15 эту колоду для получения более подробной информации - так что поведение, которое вы видите, ожидается.
Реальный вопрос в том, почему элемент заканчивается как kSecAttrAccessibleWhenUnlocked
, пока вы думаете, что он kSecAttrAccessibleAlways
. Трудно сказать, не видя больше кода и/или имея больше информации, но вот несколько вещей, которые следует учитывать:
- Элементы связки ключей не удаляются, когда приложение удаляется - они переустанавливают/обновляют приложение. Поэтому, если более ранняя версия приложения создала элемент как
kSecAttrAccessibleWhenUnlocked
, он мог бы просто продолжить. Попробуйте удалить элемент и создать его снова (и проверить возвращаемые значения SecItemDelete()
и SecItemAdd()
, чтобы убедиться в этом).
- Двойная проверка, что
kSecAttrAccessibleAlways
передается на SecItemAdd()
, так что iOS не применяет значения по умолчанию самостоятельно.
- Обратите внимание, что класс доступности должен быть передан при создании элемента (т.е. до
SecItemAdd()
), а не при его извлечении (т.е. не в SecItemCopyMatching()
). Это очевидно, но никогда не мешает повторять.
Если ни одно из приведенных выше вопросов не поможет, разместите соответствующий код, показывающий, как создается элемент, а затем как он читается.
Ответ 2
Доступ к цепочке ключей заблокирован, когда у вас есть пароль на устройстве, и устройство заблокировано. Поэтому, если у вас есть пароль, вы не можете делать какие-либо действия с keychain из экрана блокировки.