Path: blob/master/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.cpp
40957 views
/*1* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* A class to track key JVM instance info from the AT WinAccessBridge27*/2829#include "AccessBridgeDebug.h"30#include "AccessBridgeJavaVMInstance.h"31#include "AccessBridgeMessages.h"32#include "AccessBridgePackages.h"33#include "accessBridgeResource.h" // for debugging messages3435#include <winbase.h>36#include <jni.h>3738// The initialization must only be done one time and to provide for that the initialization39// is now done in WinAccessBridge and the CRITICAL_SECTION memory has been moved to there.40// send memory lock41//CRITICAL_SECTION sendMemoryIPCLock;42extern CRITICAL_SECTION sendMemoryIPCLock;4344// protects the javaVMs chain while in use45extern bool isVMInstanceChainInUse;4647DEBUG_CODE(extern HWND theDialogWindow);48extern "C" {49DEBUG_CODE(void AppendToCallInfo(char *s));50}515253/**54*55*56*/57AccessBridgeJavaVMInstance::AccessBridgeJavaVMInstance(HWND ourABWindow,58HWND javaABWindow,59long javaVMID,60AccessBridgeJavaVMInstance *next) {61goingAway = FALSE;62// This should be called once. Moved to WinAccessBridge c'tor63//InitializeCriticalSection(&sendMemoryIPCLock);64ourAccessBridgeWindow = ourABWindow;65javaAccessBridgeWindow = javaABWindow;66vmID = javaVMID;67nextJVMInstance = next;68memoryMappedFileMapHandle = (HANDLE) 0;69memoryMappedView = (char *) 0;70sprintf(memoryMappedFileName, "AccessBridge-%p-%p.mmf",71ourAccessBridgeWindow, javaAccessBridgeWindow);72}7374/**75*76*77*/78AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance() {79DEBUG_CODE(char buffer[256]);8081DEBUG_CODE(AppendToCallInfo("***** in AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance\r\n"));82EnterCriticalSection(&sendMemoryIPCLock);8384// if IPC memory mapped file view is valid, unmap it85goingAway = TRUE;86if (memoryMappedView != (char *) 0) {87DEBUG_CODE(sprintf(buffer, " unmapping memoryMappedView; view = %p\r\n", memoryMappedView));88DEBUG_CODE(AppendToCallInfo(buffer));89UnmapViewOfFile(memoryMappedView);90memoryMappedView = (char *) 0;91}92// if IPC memory mapped file handle map is open, close it93if (memoryMappedFileMapHandle != (HANDLE) 0) {94DEBUG_CODE(sprintf(buffer, " closing memoryMappedFileMapHandle; handle = %p\r\n", memoryMappedFileMapHandle));95DEBUG_CODE(AppendToCallInfo(buffer));96CloseHandle(memoryMappedFileMapHandle);97memoryMappedFileMapHandle = (HANDLE) 0;98}99LeaveCriticalSection(&sendMemoryIPCLock);100101}102103/**104* initiateIPC - sets up the memory-mapped file to do IPC messaging105* 1 file is created: to handle requests for information106* initiated from Windows AT. The package is placed into107* the memory-mapped file (char *memoryMappedView),108* and then a special SendMessage() is sent. When the109* JavaDLL returns from SendMessage() processing, the110* data will be in memoryMappedView. The SendMessage()111* return value tells us if all is right with the world.112*113* The set-up proces involves creating the memory-mapped114* file, and handshaking with the JavaDLL so it knows115* about it as well.116*117*/118LRESULT119AccessBridgeJavaVMInstance::initiateIPC() {120DEBUG_CODE(char debugBuf[256]);121DWORD errorCode;122123DEBUG_CODE(AppendToCallInfo(" in AccessBridgeJavaVMInstance::initiateIPC()\r\n"));124125// create Windows-initiated IPC file & map it to a ptr126memoryMappedFileMapHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,127PAGE_READWRITE, 0,128// 8 bytes for return code129sizeof(WindowsInitiatedPackages) + 8,130memoryMappedFileName);131if (memoryMappedFileMapHandle == NULL) {132errorCode = GetLastError();133DEBUG_CODE(sprintf(debugBuf, " Failed to CreateFileMapping for %s, error: %X", memoryMappedFileName, errorCode));134DEBUG_CODE(AppendToCallInfo(debugBuf));135return errorCode;136} else {137DEBUG_CODE(sprintf(debugBuf, " CreateFileMapping worked - filename: %s\r\n", memoryMappedFileName));138DEBUG_CODE(AppendToCallInfo(debugBuf));139}140141memoryMappedView = (char *) MapViewOfFile(memoryMappedFileMapHandle,142FILE_MAP_READ | FILE_MAP_WRITE,1430, 0, 0);144if (memoryMappedView == NULL) {145errorCode = GetLastError();146DEBUG_CODE(sprintf(debugBuf, " Failed to MapViewOfFile for %s, error: %X", memoryMappedFileName, errorCode));147DEBUG_CODE(AppendToCallInfo(debugBuf));148return errorCode;149} else {150DEBUG_CODE(sprintf(debugBuf, " MapViewOfFile worked - view: %p\r\n", memoryMappedView));151DEBUG_CODE(AppendToCallInfo(debugBuf));152}153154155// write some data to the memory mapped file156strcpy(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_QUERY);157158159// inform the JavaDLL that we've a memory mapped file ready for it160char buffer[sizeof(PackageType) + sizeof(MemoryMappedFileCreatedPackage)];161PackageType *type = (PackageType *) buffer;162MemoryMappedFileCreatedPackage *pkg = (MemoryMappedFileCreatedPackage *) (buffer + sizeof(PackageType));163*type = cMemoryMappedFileCreatedPackage;164pkg->bridgeWindow = ABHandleToLong(ourAccessBridgeWindow);165strncpy(pkg->filename, memoryMappedFileName, cMemoryMappedNameSize);166sendPackage(buffer, sizeof(buffer));167168169// look for the JavaDLL's answer to see if it could read the file170if (strcmp(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_ANSWER) != 0) {171DEBUG_CODE(sprintf(debugBuf, " JavaVM failed to deal with memory mapped file %s\r\n",172memoryMappedFileName));173DEBUG_CODE(AppendToCallInfo(debugBuf));174return -1;175} else {176DEBUG_CODE(sprintf(debugBuf, " Success! JavaVM accpeted our file\r\n"));177DEBUG_CODE(AppendToCallInfo(debugBuf));178}179180return 0;181}182183// -----------------------184185/**186* sendPackage - uses SendMessage(WM_COPYDATA) to do IPC messaging187* with the Java AccessBridge DLL188*189* NOTE: WM_COPYDATA is only for one-way IPC; there190* is no way to return parameters (especially big ones)191* Use sendMemoryPackage() to do that!192*/193LRESULT194AccessBridgeJavaVMInstance::sendPackage(char *buffer, long bufsize) {195COPYDATASTRUCT toCopy;196toCopy.dwData = 0; // 32-bits we could use for something...197toCopy.cbData = bufsize;198toCopy.lpData = buffer;199200PrintDebugString("[INFO]: In AccessBridgeVMInstance::sendPackage");201PrintDebugString("[INFO]: javaAccessBridgeWindow: %p", javaAccessBridgeWindow);202/* This was SendMessage. Normally that is a blocking call. However, if203* SendMessage is sent to another process, e.g. another JVM and an incoming204* SendMessage is pending, control will be passed to the DialogProc to handle205* the incoming message. A bug occurred where this allowed an AB_DLL_GOING_AWAY206* message to be processed deleting an AccessBridgeJavaVMInstance object in207* the javaVMs chain. SendMessageTimeout with SMTO_BLOCK set will prevent the208* calling thread from processing other requests while waiting, i.e control209* will not be passed to the DialogProc. Also note that PostMessage or210* SendNotifyMessage can't be used. Although they don't allow transfer to211* the DialogProc they can't be used in cases where pointers are passed. This212* is because the referenced memory needs to be available when the other thread213* gets control.214*/215UINT flags = SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG;216DWORD_PTR out; // not used217LRESULT lr = SendMessageTimeout( javaAccessBridgeWindow, WM_COPYDATA,218(WPARAM)ourAccessBridgeWindow, (LPARAM)&toCopy,219flags, 4000, &out );220return lr;221}222223224/**225* sendMemoryPackage - uses Memory-Mapped files to do IPC messaging226* with the Java AccessBridge DLL, informing the227* Java AccessBridge DLL via SendMessage that something228* is waiting for it in the shared file...229*230* In the SendMessage call, the third param (WPARAM) is231* the source HWND (ourAccessBridgeWindow in this case),232* and the fourth param (LPARAM) is the size in bytes of233* the package put into shared memory.234*235*/236BOOL237AccessBridgeJavaVMInstance::sendMemoryPackage(char *buffer, long bufsize) {238239// Protect against race condition where the memory mapped file is240// deallocated before the memory package is being sent241if (goingAway) {242return FALSE;243}244BOOL retval = FALSE;245246DEBUG_CODE(char outputBuf[256]);247DEBUG_CODE(sprintf(outputBuf, "AccessBridgeJavaVMInstance::sendMemoryPackage(, %d)", bufsize));248DEBUG_CODE(AppendToCallInfo(outputBuf));249250DEBUG_CODE(PackageType *type = (PackageType *) buffer);251DEBUG_CODE(if (*type == cGetAccessibleTextRangePackage) {)252DEBUG_CODE(AppendToCallInfo(" 'buffer' contains:"));253DEBUG_CODE(GetAccessibleTextRangePackage *pkg = (GetAccessibleTextRangePackage *) (buffer + sizeof(PackageType)));254DEBUG_CODE(sprintf(outputBuf, " PackageType = %X", *type));255DEBUG_CODE(AppendToCallInfo(outputBuf));256DEBUG_CODE(sprintf(outputBuf, " GetAccessibleTextRange: start = %d, end = %d, rText = %ls",257pkg->start, pkg->end, pkg->rText));258DEBUG_CODE(AppendToCallInfo(outputBuf));259DEBUG_CODE(})260261EnterCriticalSection(&sendMemoryIPCLock);262{263// copy the package into shared memory264if (!goingAway) {265memcpy(memoryMappedView, buffer, bufsize);266267DEBUG_CODE(PackageType *type = (PackageType *) memoryMappedView);268DEBUG_CODE(if (*type == cGetAccessibleTextItemsPackage) {)269DEBUG_CODE(AppendToCallInfo(" 'memoryMappedView' now contains:"));270DEBUG_CODE(GetAccessibleTextItemsPackage *pkg = (GetAccessibleTextItemsPackage *) (buffer + sizeof(PackageType)));271DEBUG_CODE(sprintf(outputBuf, " PackageType = %X", *type));272DEBUG_CODE(AppendToCallInfo(outputBuf));273DEBUG_CODE(})274}275276if (!goingAway) {277// Let the recipient know there is a package waiting for them. The unset byte278// at end of buffer which will only be set if message is properly received279char *done = &memoryMappedView[bufsize];280*done = 0;281282PrintDebugString("[INFO]: javaAccessBridgeWindow: %p", javaAccessBridgeWindow);283// See the comment above the call to SendMessageTimeout in SendPackage method above.284UINT flags = SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG;285DWORD_PTR out; // not used286SendMessageTimeout( javaAccessBridgeWindow, AB_MESSAGE_WAITING, (WPARAM)ourAccessBridgeWindow, (LPARAM)bufsize,287flags, 4000, &out );288289// only succeed if message has been properly received290if(!goingAway) retval = (*done == 1);291}292293// copy the package back from shared memory294if (!goingAway) {295memcpy(buffer, memoryMappedView, bufsize);296}297}298LeaveCriticalSection(&sendMemoryIPCLock);299return retval;300}301302303/**304* findAccessBridgeWindow - walk through linked list from where we are,305* return the HWND of the ABJavaVMInstance that306* matches the passed in vmID; no match: return 0307*308*/309HWND310AccessBridgeJavaVMInstance::findAccessBridgeWindow(long javaVMID) {311PrintDebugString("[INFO]: In findAccessBridgeWindow");312// no need to recurse really313if (vmID == javaVMID) {314return javaAccessBridgeWindow;315} else {316isVMInstanceChainInUse = true;317AccessBridgeJavaVMInstance *current = nextJVMInstance;318while (current != (AccessBridgeJavaVMInstance *) 0) {319if (current->vmID == javaVMID) {320isVMInstanceChainInUse = false;321return current->javaAccessBridgeWindow;322}323current = current->nextJVMInstance;324}325isVMInstanceChainInUse = false;326}327return 0;328}329330/**331* findABJavaVMInstanceFromJavaHWND - walk through linked list from332* where we are. Return the333* AccessBridgeJavaVMInstance334* of the ABJavaVMInstance that335* matches the passed in vmID;336* no match: return 0337*/338AccessBridgeJavaVMInstance *339AccessBridgeJavaVMInstance::findABJavaVMInstanceFromJavaHWND(HWND window) {340PrintDebugString("[INFO]: In findABJavaInstanceFromJavaHWND");341// no need to recurse really342if (javaAccessBridgeWindow == window) {343return this;344} else {345isVMInstanceChainInUse = true;346AccessBridgeJavaVMInstance *current = nextJVMInstance;347while (current != (AccessBridgeJavaVMInstance *) 0) {348if (current->javaAccessBridgeWindow == window) {349isVMInstanceChainInUse = false;350return current;351}352current = current->nextJVMInstance;353}354}355isVMInstanceChainInUse = false;356return (AccessBridgeJavaVMInstance *) 0;357}358359360