UIA client detection is broken
Categories
(Core :: Disability Access APIs, defect)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox117 | --- | fixed |
People
(Reporter: Jamie, Assigned: Jamie)
References
(Blocks 1 open bug)
Details
Attachments
(1 file)
In bug 1419886 and friends, we implemented support for detecting the UI Automation client which instantiated accessibility. The executable name showed up in about:support and telemetry. Unfortunately, that broke some time ago. We need to figure out why and hopefully fix it.
| Assignee | ||
Comment 1•2 years ago
|
||
My findings so far:
- We watch for a dll-loaded-main-thread observer topic to detect when UIAutomationCore.dll is loaded and use that to trigger initialisation of UIA detection. If Narrator is running before Firefox starts, it seems that we don't get this notification early enough. It definitely fires, but it's already too late by the time it does. I guess the observer notification fires async and the window gets shown before it fires.
- I confirmed that UIAutomationCore.dll still always seems to load on the main thread, even though we get the notification too late.
- Even if Narrator is started after Firefox, we never receive the "HOOKUTIL_MSG" window message. That string isn't anywhere in UIAutomationCore.dll on Windows 11.
- There is "HOOKUTIL_SYNC_MSG", but we never seem to get that message either.
- A message we do get is "UiaServerConnection_HookMessage", but that doesn't seem to take the same arguments.
- Edge has support for UIA client detection in chrome://accessibility. That's not available in Chrome and I can't find any source code for it. However, it seems that is broken as well!
| Assignee | ||
Comment 2•2 years ago
|
||
The HOOKUTIL_MSG string doesn't exist in UIAutomationCore.dll on Windows 10 21h1 either, so I guess this has been broken since an earlier build of Windows 10 or perhaps even an earlier version of Windows (8.1, 8 or 7).
| Assignee | ||
Comment 3•2 years ago
•
|
||
I was hoping the WM_GETOBJECT message might contain useful info in the wparam. Unfortunately, it's always 0. Intriguingly, it seems to be sent from another process (probably the client), rather than sent in-process by UIAutomationCore like the MSAA proxy queries are.
| Assignee | ||
Comment 4•2 years ago
•
|
||
Using WinObjEx64, I wasn't able to find any HOOK_SHMEM "section" objects. Given that HOOKUTIL_MSG and HOOKUTIL_SYNC_MSG never seem to be received, I'm thinking this is no longer used.
The UiaServerConnection_HookMessage doesn't seem to provide anything useful. There is a number which seems to increment (for each connection perhaps?) and another number which is always < 10.
More promising, using Process Explorer, I was able to find UIA named pipe objects in the form "\Device\NamedPipe\UIA_PIPE_16124_56450b81", where 16124 is the Firefox parent process id. Clients also get a handle to this pipe. Each client gets its own pipe. For example, i ran both NVDA and Narrator simultaneously. NVDA connected to \Device\NamedPipe\UIA_PIPE_16124_56450b81, while Narrator connected to \Device\NamedPipe\UIA_PIPE_16124_1d870675. Note that you use \.\pipe\name when accessing this via file system calls, rather than \Device\NamedPipe (which I assume relates to the kernel object directory).
The question is how we can use this information. I'm not sure if our code for iterating Windows handles can tell us which pipe each handle is associated with. There is GetNamedPipeClientProcessId, but that requires the specific pipe handle which we probably can't access. I also found this code for listing named pipes which we might need to find the pipe in question.
| Assignee | ||
Comment 5•2 years ago
|
||
Process Explorer can't see the handle for NVDA when Process Explorer isn't running as administrator, presumably because NVDA runs with the uiAccess privilege. That could be a problem, though our current approach solved that problem for the old UIAutomationCore - see bug 1423999 - so perhaps it's solvable.
| Assignee | ||
Comment 6•2 years ago
|
||
If we can at least get the actual handle in our process, we should be able to use GetNamedPipeClientProcessId. But I'm not yet sure how to get the pipe name from the data structure we get when iterating handles.
| Assignee | ||
Comment 7•2 years ago
•
|
||
Since we can't hook any useful UIA message, we can't block UIA that way. Even if we could, we have the dll load notification timing problem: we don't get the notification soon enough to set a hook in time.
Instead, I'm thinking we can check for the UIA client process id in LazyInstantiator if the COM (MSAA) client thread id is 0. We'll need to shuffle some stuff around though with respect to how we log the instantiator. Maybe we should call ShouldInstantiate with a process id retrieved from either mscom::ProcessRuntime::GetClientThreadId or, if that is 0, our UIA detection code. That way, ShouldInstantiate can set the instantiator using the process id, rather than our UIA detection code setting that separately.
If we go down this path, we'll also want to remove all the UIA hooking stuff in nsAppShell. CompatibilityUIA would then just be the code to figure out the UIA client process id.
| Assignee | ||
Comment 8•2 years ago
|
||
The window message we previously hooked no longer gets sent and the associated shared memory no longer seems to be created either.
Also, we don't seem to be notified about the load of UIAutomationCore.dll until after it has already instantiated a11y, which is obviously too late for us to hook anything.
Instead, we block UIA instantiation via LazyInstantiator, just as we do for MSAA/IA2:
- Refactor CompatibilityUIA so that rather than being called by a hook, it simply allows the caller to query the process id of the UIA client, if any.
- CompatibilityUIA now searches handles in our process for a named pipe created by UIA for communication with the remote process and then uses GetNamedPipeServerProcessId to get the process id on the other end of the pipe.
- Refactor LazyInstantiator so that it first tries to get the MSAA/IA2 client process id, then calls CompatibilityUIA to get the UIA client process id.
- LazyInstantiator now handles setting the instantiator and blocking of clients for UIA as well as MSAA/IA2 using the same code.
Comment 10•2 years ago
•
|
||
Backed out for causing build bustages.
[task 2023-07-13T04:12:14.264Z] 04:12:14 INFO - In file included from Unified_cpp_windows_msaa0.cpp:29:
[task 2023-07-13T04:12:14.264Z] 04:12:14 ERROR - /builds/worker/checkouts/gecko/accessible/windows/msaa/CompatibilityUIA.cpp:90:23: error: no member named 'mName' in '_OBJECT_NAME_INFORMATION'; did you mean 'Name'?
[task 2023-07-13T04:12:14.264Z] 04:12:14 INFO - if (!objNameInfo->mName.Length) {
[task 2023-07-13T04:12:14.264Z] 04:12:14 INFO - ^~~~~
[task 2023-07-13T04:12:14.264Z] 04:12:14 INFO - Name
[task 2023-07-13T04:12:14.264Z] 04:12:14 INFO - /builds/worker/fetches/clang/bin/../i686-w64-mingw32/include/winternl.h:248:20: note: 'Name' declared here
[task 2023-07-13T04:12:14.265Z] 04:12:14 INFO - UNICODE_STRING Name;
[task 2023-07-13T04:12:14.265Z] 04:12:14 INFO - ^
[task 2023-07-13T04:12:14.265Z] 04:12:14 INFO - In file included from Unified_cpp_windows_msaa0.cpp:29:
[task 2023-07-13T04:12:14.265Z] 04:12:14 ERROR - /builds/worker/checkouts/gecko/accessible/windows/msaa/CompatibilityUIA.cpp:93:44: error: no member named 'mName' in '_OBJECT_NAME_INFORMATION'; did you mean 'Name'?
[task 2023-07-13T04:12:14.265Z] 04:12:14 INFO - nsDependentString objName(objNameInfo->mName.Buffer,
[task 2023-07-13T04:12:14.265Z] 04:12:14 INFO - ^~~~~
[task 2023-07-13T04:12:14.265Z] 04:12:14 INFO - Name
[task 2023-07-13T04:12:14.265Z] 04:12:14 INFO - /builds/worker/fetches/clang/bin/../i686-w64-mingw32/include/winternl.h:248:20: note: 'Name' declared here
[task 2023-07-13T04:12:14.266Z] 04:12:14 INFO - UNICODE_STRING Name;
[task 2023-07-13T04:12:14.266Z] 04:12:14 INFO - ^
[task 2023-07-13T04:12:14.266Z] 04:12:14 INFO - In file included from Unified_cpp_windows_msaa0.cpp:29:
[task 2023-07-13T04:12:14.266Z] 04:12:14 ERROR - /builds/worker/checkouts/gecko/accessible/windows/msaa/CompatibilityUIA.cpp:94:44: error: no member named 'mName' in '_OBJECT_NAME_INFORMATION'
[task 2023-07-13T04:12:14.266Z] 04:12:14 INFO - objNameInfo->mName.Length / sizeof(wchar_t));
[task 2023-07-13T04:12:14.266Z] 04:12:14 INFO - ~~~~~~~~~~~ ^
[task 2023-07-13T04:12:14.266Z] 04:12:14 INFO - In file included from Unified_cpp_windows_msaa0.cpp:38:
[task 2023-07-13T04:12:14.266Z] 04:12:14 INFO - In file included from /builds/worker/checkouts/gecko/accessible/windows/msaa/DocAccessibleWrap.cpp:16:
[task 2023-07-13T04:12:14.266Z] 04:12:14 INFO - In file included from /builds/worker/checkouts/gecko/accessible/windows/sdn/sdnDocAccessible.h:13:
[task 2023-07-13T04:12:14.267Z] 04:12:14 INFO - In file included from /builds/worker/checkouts/gecko/accessible/windows/msaa/MsaaDocAccessible.h:10:
[task 2023-07-13T04:12:14.267Z] 04:12:14 WARNING - /builds/worker/checkouts/gecko/accessible/windows/ia2/ia2AccessibleHypertext.h:29:3: warning: 'QueryInterface' overrides a member function but is not marked 'override' [-Winconsistent-missing-override]
[task 2023-07-13T04:12:14.267Z] 04:12:14 INFO - DECL_IUNKNOWN_INHERITED
[task 2023-07-13T04:12:14.267Z] 04:12:14 INFO - ^
[task 2023-07-13T04:12:14.267Z] 04:12:14 INFO - /builds/worker/checkouts/gecko/accessible/windows/msaa/IUnknownImpl.h:74:37: note: expanded from macro 'DECL_IUNKNOWN_INHERITED'
[task 2023-07-13T04:12:14.267Z] 04:12:14 INFO - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**);
[task 2023-07-13T04:12:14.267Z] 04:12:14 INFO - ^
[task 2023-07-13T04:12:14.267Z] 04:12:14 INFO - /builds/worker/fetches/clang/bin/../i686-w64-mingw32/include/unknwnbase.h:86:39: note: overridden virtual function is here
[task 2023-07-13T04:12:14.268Z] 04:12:14 INFO - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) = 0;
[task 2023-07-13T04:12:14.268Z] 04:12:14 INFO - ^
[task 2023-07-13T04:12:14.268Z] 04:12:14 INFO - In file included from Unified_cpp_windows_msaa0.cpp:38:
[task 2023-07-13T04:12:14.268Z] 04:12:14 INFO - In file included from /builds/worker/checkouts/gecko/accessible/windows/msaa/DocAccessibleWrap.cpp:16:
Comment 11•2 years ago
|
||
| Assignee | ||
Updated•2 years ago
|
Comment 12•2 years ago
|
||
| bugherder | ||
| Assignee | ||
Comment 13•2 years ago
|
||
I've confirmed that this works on:
Windows 11 Version 21H2 (OS Build 22000.2176)
Windows 11 Version 22H2 (OS Build 22621.1992)
Example:
Accessibility Instantiator
UIAUTOMATION|C:\Windows\System32\Narrator.exe
It does not work on Windows 10 21H1. Example:
Accessibility Instantiator
UIAUTOMATION|
I'm not too concerned about that, as it's EOL anyway.
I'm trying to update that machine to Windows 10 22H2 to see if it works there.
| Assignee | ||
Comment 14•2 years ago
|
||
This doesn't work on Windows 10 22H2. I'll need to look into that.
| Assignee | ||
Comment 15•2 years ago
|
||
On Windows 10, UIA named pipes are never created for Firefox, even though they are created for other processes. Maybe pipes aren't created for things which use the MSAA/IA2 proxy? I'll try to debug this further.
Description
•