Commit 7c094a26 authored by liang.tang's avatar liang.tang
Browse files

arthas-master

parents
Pipeline #220 failed with stages
in 0 seconds
/*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* Note: In addition to this header file AccessBridgeCalls.c must be compiled and
* linked to your application. AccessBridgeCalls.c implements the Java Access
* Bridge API and also hides the complexities associated with interfacing to the
* associated Java Access Bridge DLL which is installed when Java is installed.
*
* AccessBridgeCalls.c is available for download from the OpenJDK repository using
* the following link:
*
* http://hg.openjdk.java.net/jdk9/jdk9/jdk/raw-file/tip/src/jdk.accessibility/windows/native/bridge/AccessBridgeCalls.c
*
* Also note that the API is used in the jaccessinspector and jaccesswalker tools.
* The source for those tools is available in the OpenJDK repository at these links:
*
* http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp
* http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp
*
*
*/
/*
* Wrapper functions around calls to the AccessBridge DLL
*/
#include <windows.h>
#include <jni.h>
#include "AccessBridgeCallbacks.h"
#include "AccessBridgePackages.h"
#ifdef __cplusplus
extern "C" {
#endif
#define null NULL
typedef JOBJECT64 AccessibleContext;
typedef JOBJECT64 AccessibleText;
typedef JOBJECT64 AccessibleValue;
typedef JOBJECT64 AccessibleSelection;
typedef JOBJECT64 Java_Object;
typedef JOBJECT64 PropertyChangeEvent;
typedef JOBJECT64 FocusEvent;
typedef JOBJECT64 CaretEvent;
typedef JOBJECT64 MouseEvent;
typedef JOBJECT64 MenuEvent;
typedef JOBJECT64 AccessibleTable;
typedef JOBJECT64 AccessibleHyperlink;
typedef JOBJECT64 AccessibleHypertext;
typedef void (*Windows_runFP) ();
typedef void (*SetPropertyChangeFP) (AccessBridge_PropertyChangeFP fp);
typedef void (*SetJavaShutdownFP) (AccessBridge_JavaShutdownFP fp);
typedef void (*SetFocusGainedFP) (AccessBridge_FocusGainedFP fp);
typedef void (*SetFocusLostFP) (AccessBridge_FocusLostFP fp);
typedef void (*SetCaretUpdateFP) (AccessBridge_CaretUpdateFP fp);
typedef void (*SetMouseClickedFP) (AccessBridge_MouseClickedFP fp);
typedef void (*SetMouseEnteredFP) (AccessBridge_MouseEnteredFP fp);
typedef void (*SetMouseExitedFP) (AccessBridge_MouseExitedFP fp);
typedef void (*SetMousePressedFP) (AccessBridge_MousePressedFP fp);
typedef void (*SetMouseReleasedFP) (AccessBridge_MouseReleasedFP fp);
typedef void (*SetMenuCanceledFP) (AccessBridge_MenuCanceledFP fp);
typedef void (*SetMenuDeselectedFP) (AccessBridge_MenuDeselectedFP fp);
typedef void (*SetMenuSelectedFP) (AccessBridge_MenuSelectedFP fp);
typedef void (*SetPopupMenuCanceledFP) (AccessBridge_PopupMenuCanceledFP fp);
typedef void (*SetPopupMenuWillBecomeInvisibleFP) (AccessBridge_PopupMenuWillBecomeInvisibleFP fp);
typedef void (*SetPopupMenuWillBecomeVisibleFP) (AccessBridge_PopupMenuWillBecomeVisibleFP fp);
typedef void (*SetPropertyNameChangeFP) (AccessBridge_PropertyNameChangeFP fp);
typedef void (*SetPropertyDescriptionChangeFP) (AccessBridge_PropertyDescriptionChangeFP fp);
typedef void (*SetPropertyStateChangeFP) (AccessBridge_PropertyStateChangeFP fp);
typedef void (*SetPropertyValueChangeFP) (AccessBridge_PropertyValueChangeFP fp);
typedef void (*SetPropertySelectionChangeFP) (AccessBridge_PropertySelectionChangeFP fp);
typedef void (*SetPropertyTextChangeFP) (AccessBridge_PropertyTextChangeFP fp);
typedef void (*SetPropertyCaretChangeFP) (AccessBridge_PropertyCaretChangeFP fp);
typedef void (*SetPropertyVisibleDataChangeFP) (AccessBridge_PropertyVisibleDataChangeFP fp);
typedef void (*SetPropertyChildChangeFP) (AccessBridge_PropertyChildChangeFP fp);
typedef void (*SetPropertyActiveDescendentChangeFP) (AccessBridge_PropertyActiveDescendentChangeFP fp);
typedef void (*SetPropertyTableModelChangeFP) (AccessBridge_PropertyTableModelChangeFP fp);
typedef void (*ReleaseJavaObjectFP) (long vmID, Java_Object object);
typedef BOOL (*GetVersionInfoFP) (long vmID, AccessBridgeVersionInfo *info);
typedef BOOL (*IsJavaWindowFP) (HWND window);
typedef BOOL (*IsSameObjectFP) (long vmID, JOBJECT64 obj1, JOBJECT64 obj2);
typedef BOOL (*GetAccessibleContextFromHWNDFP) (HWND window, long *vmID, AccessibleContext *ac);
typedef HWND (*getHWNDFromAccessibleContextFP) (long vmID, AccessibleContext ac);
typedef BOOL (*GetAccessibleContextAtFP) (long vmID, AccessibleContext acParent,
jint x, jint y, AccessibleContext *ac);
typedef BOOL (*GetAccessibleContextWithFocusFP) (HWND window, long *vmID, AccessibleContext *ac);
typedef BOOL (*GetAccessibleContextInfoFP) (long vmID, AccessibleContext ac, AccessibleContextInfo *info);
typedef AccessibleContext (*GetAccessibleChildFromContextFP) (long vmID, AccessibleContext ac, jint i);
typedef AccessibleContext (*GetAccessibleParentFromContextFP) (long vmID, AccessibleContext ac);
/* begin AccessibleTable */
typedef BOOL (*getAccessibleTableInfoFP) (long vmID, AccessibleContext ac, AccessibleTableInfo *tableInfo);
typedef BOOL (*getAccessibleTableCellInfoFP) (long vmID, AccessibleTable accessibleTable,
jint row, jint column, AccessibleTableCellInfo *tableCellInfo);
typedef BOOL (*getAccessibleTableRowHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
typedef BOOL (*getAccessibleTableColumnHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
typedef AccessibleContext (*getAccessibleTableRowDescriptionFP) (long vmID, AccessibleContext acParent, jint row);
typedef AccessibleContext (*getAccessibleTableColumnDescriptionFP) (long vmID, AccessibleContext acParent, jint column);
typedef jint (*getAccessibleTableRowSelectionCountFP) (long vmID, AccessibleTable table);
typedef BOOL (*isAccessibleTableRowSelectedFP) (long vmID, AccessibleTable table, jint row);
typedef BOOL (*getAccessibleTableRowSelectionsFP) (long vmID, AccessibleTable table, jint count,
jint *selections);
typedef jint (*getAccessibleTableColumnSelectionCountFP) (long vmID, AccessibleTable table);
typedef BOOL (*isAccessibleTableColumnSelectedFP) (long vmID, AccessibleTable table, jint column);
typedef BOOL (*getAccessibleTableColumnSelectionsFP) (long vmID, AccessibleTable table, jint count,
jint *selections);
typedef jint (*getAccessibleTableRowFP) (long vmID, AccessibleTable table, jint index);
typedef jint (*getAccessibleTableColumnFP) (long vmID, AccessibleTable table, jint index);
typedef jint (*getAccessibleTableIndexFP) (long vmID, AccessibleTable table, jint row, jint column);
/* end AccessibleTable */
/* AccessibleRelationSet */
typedef BOOL (*getAccessibleRelationSetFP) (long vmID, AccessibleContext accessibleContext,
AccessibleRelationSetInfo *relationSetInfo);
/* AccessibleHypertext */
typedef BOOL (*getAccessibleHypertextFP)(long vmID, AccessibleContext accessibleContext,
AccessibleHypertextInfo *hypertextInfo);
typedef BOOL (*activateAccessibleHyperlinkFP)(long vmID, AccessibleContext accessibleContext,
AccessibleHyperlink accessibleHyperlink);
typedef jint (*getAccessibleHyperlinkCountFP)(const long vmID,
const AccessibleContext accessibleContext);
typedef BOOL (*getAccessibleHypertextExtFP) (const long vmID,
const AccessibleContext accessibleContext,
const jint nStartIndex,
AccessibleHypertextInfo *hypertextInfo);
typedef jint (*getAccessibleHypertextLinkIndexFP)(const long vmID,
const AccessibleHypertext hypertext,
const jint nIndex);
typedef BOOL (*getAccessibleHyperlinkFP)(const long vmID,
const AccessibleHypertext hypertext,
const jint nIndex,
AccessibleHyperlinkInfo *hyperlinkInfo);
/* Accessible KeyBindings, Icons and Actions */
typedef BOOL (*getAccessibleKeyBindingsFP)(long vmID, AccessibleContext accessibleContext,
AccessibleKeyBindings *keyBindings);
typedef BOOL (*getAccessibleIconsFP)(long vmID, AccessibleContext accessibleContext,
AccessibleIcons *icons);
typedef BOOL (*getAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext,
AccessibleActions *actions);
typedef BOOL (*doAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext,
AccessibleActionsToDo *actionsToDo, jint *failure);
/* AccessibleText */
typedef BOOL (*GetAccessibleTextInfoFP) (long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y);
typedef BOOL (*GetAccessibleTextItemsFP) (long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index);
typedef BOOL (*GetAccessibleTextSelectionInfoFP) (long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection);
typedef BOOL (*GetAccessibleTextAttributesFP) (long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes);
typedef BOOL (*GetAccessibleTextRectFP) (long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index);
typedef BOOL (*GetAccessibleTextLineBoundsFP) (long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex);
typedef BOOL (*GetAccessibleTextRangeFP) (long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len);
typedef BOOL (*GetCurrentAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
typedef BOOL (*GetMaximumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
typedef BOOL (*GetMinimumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
typedef void (*AddAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
typedef void (*ClearAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as);
typedef JOBJECT64 (*GetAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
typedef int (*GetAccessibleSelectionCountFromContextFP) (long vmID, AccessibleSelection as);
typedef BOOL (*IsAccessibleChildSelectedFromContextFP) (long vmID, AccessibleSelection as, int i);
typedef void (*RemoveAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
typedef void (*SelectAllAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as);
/* Utility methods */
typedef BOOL (*setTextContentsFP) (const long vmID, const AccessibleContext ac, const wchar_t *text);
typedef AccessibleContext (*getParentWithRoleFP) (const long vmID, const AccessibleContext ac, const wchar_t *role);
typedef AccessibleContext (*getParentWithRoleElseRootFP) (const long vmID, const AccessibleContext ac, const wchar_t *role);
typedef AccessibleContext (*getTopLevelObjectFP) (const long vmID, const AccessibleContext ac);
typedef int (*getObjectDepthFP) (const long vmID, const AccessibleContext ac);
typedef AccessibleContext (*getActiveDescendentFP) (const long vmID, const AccessibleContext ac);
typedef BOOL (*getVirtualAccessibleNameFP) (const long vmID, const AccessibleContext accessibleContext,
wchar_t *name, int len);
typedef BOOL (*requestFocusFP) (const long vmID, const AccessibleContext accessibleContext);
typedef BOOL (*selectTextRangeFP) (const long vmID, const AccessibleContext accessibleContext,
const int startIndex, const int endIndex);
typedef BOOL (*getTextAttributesInRangeFP) (const long vmID, const AccessibleContext accessibleContext,
const int startIndex, const int endIndex,
AccessibleTextAttributesInfo *attributes, short *len);
typedef int (*getVisibleChildrenCountFP) (const long vmID, const AccessibleContext accessibleContext);
typedef BOOL (*getVisibleChildrenFP) (const long vmID, const AccessibleContext accessibleContext,
const int startIndex, VisibleChildrenInfo *children);
typedef BOOL (*setCaretPositionFP) (const long vmID, const AccessibleContext accessibleContext, const int position);
typedef BOOL (*getCaretLocationFP) (long vmID, AccessibleContext ac, AccessibleTextRectInfo *rectInfo, jint index);
typedef int (*getEventsWaitingFP) ();
typedef struct AccessBridgeFPsTag {
Windows_runFP Windows_run;
SetPropertyChangeFP SetPropertyChange;
SetJavaShutdownFP SetJavaShutdown;
SetFocusGainedFP SetFocusGained;
SetFocusLostFP SetFocusLost;
SetCaretUpdateFP SetCaretUpdate;
SetMouseClickedFP SetMouseClicked;
SetMouseEnteredFP SetMouseEntered;
SetMouseExitedFP SetMouseExited;
SetMousePressedFP SetMousePressed;
SetMouseReleasedFP SetMouseReleased;
SetMenuCanceledFP SetMenuCanceled;
SetMenuDeselectedFP SetMenuDeselected;
SetMenuSelectedFP SetMenuSelected;
SetPopupMenuCanceledFP SetPopupMenuCanceled;
SetPopupMenuWillBecomeInvisibleFP SetPopupMenuWillBecomeInvisible;
SetPopupMenuWillBecomeVisibleFP SetPopupMenuWillBecomeVisible;
SetPropertyNameChangeFP SetPropertyNameChange;
SetPropertyDescriptionChangeFP SetPropertyDescriptionChange;
SetPropertyStateChangeFP SetPropertyStateChange;
SetPropertyValueChangeFP SetPropertyValueChange;
SetPropertySelectionChangeFP SetPropertySelectionChange;
SetPropertyTextChangeFP SetPropertyTextChange;
SetPropertyCaretChangeFP SetPropertyCaretChange;
SetPropertyVisibleDataChangeFP SetPropertyVisibleDataChange;
SetPropertyChildChangeFP SetPropertyChildChange;
SetPropertyActiveDescendentChangeFP SetPropertyActiveDescendentChange;
SetPropertyTableModelChangeFP SetPropertyTableModelChange;
ReleaseJavaObjectFP ReleaseJavaObject;
GetVersionInfoFP GetVersionInfo;
IsJavaWindowFP IsJavaWindow;
IsSameObjectFP IsSameObject;
GetAccessibleContextFromHWNDFP GetAccessibleContextFromHWND;
getHWNDFromAccessibleContextFP getHWNDFromAccessibleContext;
GetAccessibleContextAtFP GetAccessibleContextAt;
GetAccessibleContextWithFocusFP GetAccessibleContextWithFocus;
GetAccessibleContextInfoFP GetAccessibleContextInfo;
GetAccessibleChildFromContextFP GetAccessibleChildFromContext;
GetAccessibleParentFromContextFP GetAccessibleParentFromContext;
getAccessibleTableInfoFP getAccessibleTableInfo;
getAccessibleTableCellInfoFP getAccessibleTableCellInfo;
getAccessibleTableRowHeaderFP getAccessibleTableRowHeader;
getAccessibleTableColumnHeaderFP getAccessibleTableColumnHeader;
getAccessibleTableRowDescriptionFP getAccessibleTableRowDescription;
getAccessibleTableColumnDescriptionFP getAccessibleTableColumnDescription;
getAccessibleTableRowSelectionCountFP getAccessibleTableRowSelectionCount;
isAccessibleTableRowSelectedFP isAccessibleTableRowSelected;
getAccessibleTableRowSelectionsFP getAccessibleTableRowSelections;
getAccessibleTableColumnSelectionCountFP getAccessibleTableColumnSelectionCount;
isAccessibleTableColumnSelectedFP isAccessibleTableColumnSelected;
getAccessibleTableColumnSelectionsFP getAccessibleTableColumnSelections;
getAccessibleTableRowFP getAccessibleTableRow;
getAccessibleTableColumnFP getAccessibleTableColumn;
getAccessibleTableIndexFP getAccessibleTableIndex;
getAccessibleRelationSetFP getAccessibleRelationSet;
getAccessibleHypertextFP getAccessibleHypertext;
activateAccessibleHyperlinkFP activateAccessibleHyperlink;
getAccessibleHyperlinkCountFP getAccessibleHyperlinkCount;
getAccessibleHypertextExtFP getAccessibleHypertextExt;
getAccessibleHypertextLinkIndexFP getAccessibleHypertextLinkIndex;
getAccessibleHyperlinkFP getAccessibleHyperlink;
getAccessibleKeyBindingsFP getAccessibleKeyBindings;
getAccessibleIconsFP getAccessibleIcons;
getAccessibleActionsFP getAccessibleActions;
doAccessibleActionsFP doAccessibleActions;
GetAccessibleTextInfoFP GetAccessibleTextInfo;
GetAccessibleTextItemsFP GetAccessibleTextItems;
GetAccessibleTextSelectionInfoFP GetAccessibleTextSelectionInfo;
GetAccessibleTextAttributesFP GetAccessibleTextAttributes;
GetAccessibleTextRectFP GetAccessibleTextRect;
GetAccessibleTextLineBoundsFP GetAccessibleTextLineBounds;
GetAccessibleTextRangeFP GetAccessibleTextRange;
GetCurrentAccessibleValueFromContextFP GetCurrentAccessibleValueFromContext;
GetMaximumAccessibleValueFromContextFP GetMaximumAccessibleValueFromContext;
GetMinimumAccessibleValueFromContextFP GetMinimumAccessibleValueFromContext;
AddAccessibleSelectionFromContextFP AddAccessibleSelectionFromContext;
ClearAccessibleSelectionFromContextFP ClearAccessibleSelectionFromContext;
GetAccessibleSelectionFromContextFP GetAccessibleSelectionFromContext;
GetAccessibleSelectionCountFromContextFP GetAccessibleSelectionCountFromContext;
IsAccessibleChildSelectedFromContextFP IsAccessibleChildSelectedFromContext;
RemoveAccessibleSelectionFromContextFP RemoveAccessibleSelectionFromContext;
SelectAllAccessibleSelectionFromContextFP SelectAllAccessibleSelectionFromContext;
setTextContentsFP setTextContents;
getParentWithRoleFP getParentWithRole;
getTopLevelObjectFP getTopLevelObject;
getParentWithRoleElseRootFP getParentWithRoleElseRoot;
getObjectDepthFP getObjectDepth;
getActiveDescendentFP getActiveDescendent;
getVirtualAccessibleNameFP getVirtualAccessibleName;
requestFocusFP requestFocus;
selectTextRangeFP selectTextRange;
getTextAttributesInRangeFP getTextAttributesInRange;
getVisibleChildrenCountFP getVisibleChildrenCount;
getVisibleChildrenFP getVisibleChildren;
setCaretPositionFP setCaretPosition;
getCaretLocationFP getCaretLocation;
getEventsWaitingFP getEventsWaiting;
} AccessBridgeFPs;
/**
* Initialize the world
*/
BOOL initializeAccessBridge();
BOOL shutdownAccessBridge();
/**
* Window routines
*/
BOOL IsJavaWindow(HWND window);
// Returns the virtual machine ID and AccessibleContext for a top-level window
BOOL GetAccessibleContextFromHWND(HWND target, long *vmID, AccessibleContext *ac);
// Returns the HWND from the AccessibleContext of a top-level window
HWND getHWNDFromAccessibleContext(long vmID, AccessibleContext ac);
/**
* Event handling routines
*/
void SetJavaShutdown(AccessBridge_JavaShutdownFP fp);
void SetFocusGained(AccessBridge_FocusGainedFP fp);
void SetFocusLost(AccessBridge_FocusLostFP fp);
void SetCaretUpdate(AccessBridge_CaretUpdateFP fp);
void SetMouseClicked(AccessBridge_MouseClickedFP fp);
void SetMouseEntered(AccessBridge_MouseEnteredFP fp);
void SetMouseExited(AccessBridge_MouseExitedFP fp);
void SetMousePressed(AccessBridge_MousePressedFP fp);
void SetMouseReleased(AccessBridge_MouseReleasedFP fp);
void SetMenuCanceled(AccessBridge_MenuCanceledFP fp);
void SetMenuDeselected(AccessBridge_MenuDeselectedFP fp);
void SetMenuSelected(AccessBridge_MenuSelectedFP fp);
void SetPopupMenuCanceled(AccessBridge_PopupMenuCanceledFP fp);
void SetPopupMenuWillBecomeInvisible(AccessBridge_PopupMenuWillBecomeInvisibleFP fp);
void SetPopupMenuWillBecomeVisible(AccessBridge_PopupMenuWillBecomeVisibleFP fp);
void SetPropertyNameChange(AccessBridge_PropertyNameChangeFP fp);
void SetPropertyDescriptionChange(AccessBridge_PropertyDescriptionChangeFP fp);
void SetPropertyStateChange(AccessBridge_PropertyStateChangeFP fp);
void SetPropertyValueChange(AccessBridge_PropertyValueChangeFP fp);
void SetPropertySelectionChange(AccessBridge_PropertySelectionChangeFP fp);
void SetPropertyTextChange(AccessBridge_PropertyTextChangeFP fp);
void SetPropertyCaretChange(AccessBridge_PropertyCaretChangeFP fp);
void SetPropertyVisibleDataChange(AccessBridge_PropertyVisibleDataChangeFP fp);
void SetPropertyChildChange(AccessBridge_PropertyChildChangeFP fp);
void SetPropertyActiveDescendentChange(AccessBridge_PropertyActiveDescendentChangeFP fp);
void SetPropertyTableModelChange(AccessBridge_PropertyTableModelChangeFP fp);
/**
* General routines
*/
void ReleaseJavaObject(long vmID, Java_Object object);
BOOL GetVersionInfo(long vmID, AccessBridgeVersionInfo *info);
HWND GetHWNDFromAccessibleContext(long vmID, JOBJECT64 accesibleContext);
/**
* Accessible Context routines
*/
BOOL GetAccessibleContextAt(long vmID, AccessibleContext acParent,
jint x, jint y, AccessibleContext *ac);
BOOL GetAccessibleContextWithFocus(HWND window, long *vmID, AccessibleContext *ac);
BOOL GetAccessibleContextInfo(long vmID, AccessibleContext ac, AccessibleContextInfo *info);
AccessibleContext GetAccessibleChildFromContext(long vmID, AccessibleContext ac, jint index);
AccessibleContext GetAccessibleParentFromContext(long vmID, AccessibleContext ac);
/**
* Accessible Text routines
*/
BOOL GetAccessibleTextInfo(long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y);
BOOL GetAccessibleTextItems(long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index);
BOOL GetAccessibleTextSelectionInfo(long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection);
BOOL GetAccessibleTextAttributes(long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes);
BOOL GetAccessibleTextRect(long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index);
BOOL GetAccessibleTextLineBounds(long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex);
BOOL GetAccessibleTextRange(long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len);
/* begin AccessibleTable routines */
BOOL getAccessibleTableInfo(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
BOOL getAccessibleTableCellInfo(long vmID, AccessibleTable accessibleTable, jint row, jint column,
AccessibleTableCellInfo *tableCellInfo);
BOOL getAccessibleTableRowHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
BOOL getAccessibleTableColumnHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
AccessibleContext getAccessibleTableRowDescription(long vmID, AccessibleContext acParent, jint row);
AccessibleContext getAccessibleTableColumnDescription(long vmID, AccessibleContext acParent, jint column);
jint getAccessibleTableRowSelectionCount(long vmID, AccessibleTable table);
BOOL isAccessibleTableRowSelected(long vmID, AccessibleTable table, jint row);
BOOL getAccessibleTableRowSelections(long vmID, AccessibleTable table, jint count, jint *selections);
jint getAccessibleTableColumnSelectionCount(long vmID, AccessibleTable table);
BOOL isAccessibleTableColumnSelected(long vmID, AccessibleTable table, jint column);
BOOL getAccessibleTableColumnSelections(long vmID, AccessibleTable table, jint count, jint *selections);
jint getAccessibleTableRow(long vmID, AccessibleTable table, jint index);
jint getAccessibleTableColumn(long vmID, AccessibleTable table, jint index);
jint getAccessibleTableIndex(long vmID, AccessibleTable table, jint row, jint column);
/* end AccessibleTable */
/* ----- AccessibleRelationSet routines */
BOOL getAccessibleRelationSet(long vmID, AccessibleContext accessibleContext,
AccessibleRelationSetInfo *relationSetInfo);
/* ----- AccessibleHypertext routines */
/*
* Returns hypertext information associated with a component.
*/
BOOL getAccessibleHypertext(long vmID, AccessibleContext accessibleContext,
AccessibleHypertextInfo *hypertextInfo);
/*
* Requests that a hyperlink be activated.
*/
BOOL activateAccessibleHyperlink(long vmID, AccessibleContext accessibleContext,
AccessibleHyperlink accessibleHyperlink);
/*
* Returns the number of hyperlinks in a component
* Maps to AccessibleHypertext.getLinkCount.
* Returns -1 on error.
*/
jint getAccessibleHyperlinkCount(const long vmID,
const AccessibleHypertext hypertext);
/*
* This method is used to iterate through the hyperlinks in a component. It
* returns hypertext information for a component starting at hyperlink index
* nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will
* be returned for each call to this method.
* Returns FALSE on error.
*/
BOOL getAccessibleHypertextExt(const long vmID,
const AccessibleContext accessibleContext,
const jint nStartIndex,
/* OUT */ AccessibleHypertextInfo *hypertextInfo);
/*
* Returns the index into an array of hyperlinks that is associated with
* a character index in document; maps to AccessibleHypertext.getLinkIndex
* Returns -1 on error.
*/
jint getAccessibleHypertextLinkIndex(const long vmID,
const AccessibleHypertext hypertext,
const jint nIndex);
/*
* Returns the nth hyperlink in a document
* Maps to AccessibleHypertext.getLink.
* Returns FALSE on error
*/
BOOL getAccessibleHyperlink(const long vmID,
const AccessibleHypertext hypertext,
const jint nIndex,
/* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo);
/* Accessible KeyBindings, Icons and Actions */
/*
* Returns a list of key bindings associated with a component.
*/
BOOL getAccessibleKeyBindings(long vmID, AccessibleContext accessibleContext,
AccessibleKeyBindings *keyBindings);
/*
* Returns a list of icons associate with a component.
*/
BOOL getAccessibleIcons(long vmID, AccessibleContext accessibleContext,
AccessibleIcons *icons);
/*
* Returns a list of actions that a component can perform.
*/
BOOL getAccessibleActions(long vmID, AccessibleContext accessibleContext,
AccessibleActions *actions);
/*
* Request that a list of AccessibleActions be performed by a component.
* Returns TRUE if all actions are performed. Returns FALSE
* when the first requested action fails in which case "failure"
* contains the index of the action that failed.
*/
BOOL doAccessibleActions(long vmID, AccessibleContext accessibleContext,
AccessibleActionsToDo *actionsToDo, jint *failure);
/* Additional utility methods */
/*
* Returns whether two object references refer to the same object.
*/
BOOL IsSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2);
/**
* Sets editable text contents. The AccessibleContext must implement AccessibleEditableText and
* be editable. The maximum text length that can be set is MAX_STRING_SIZE - 1.
* Returns whether successful
*/
BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text);
/**
* Returns the Accessible Context with the specified role that is the
* ancestor of a given object. The role is one of the role strings
* defined in AccessBridgePackages.h
* If there is no ancestor object that has the specified role,
* returns (AccessibleContext)0.
*/
AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext,
const wchar_t *role);
/**
* Returns the Accessible Context with the specified role that is the
* ancestor of a given object. The role is one of the role strings
* defined in AccessBridgePackages.h. If an object with the specified
* role does not exist, returns the top level object for the Java Window.
* Returns (AccessibleContext)0 on error.
*/
AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext,
const wchar_t *role);
/**
* Returns the Accessible Context for the top level object in
* a Java Window. This is same Accessible Context that is obtained
* from GetAccessibleContextFromHWND for that window. Returns
* (AccessibleContext)0 on error.
*/
AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext);
/**
* Returns how deep in the object hierarchy a given object is.
* The top most object in the object hierarchy has an object depth of 0.
* Returns -1 on error.
*/
int getObjectDepth (const long vmID, const AccessibleContext accessibleContext);
/**
* Returns the Accessible Context of the current ActiveDescendent of an object.
* This method assumes the ActiveDescendent is the component that is currently
* selected in a container object.
* Returns (AccessibleContext)0 on error or if there is no selection.
*/
AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext);
/**
/**
* Accessible Value routines
*/
BOOL GetCurrentAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
BOOL GetMaximumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
BOOL GetMinimumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
/**
* Accessible Selection routines
*/
void AddAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
void ClearAccessibleSelectionFromContext(long vmID, AccessibleSelection as);
JOBJECT64 GetAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
int GetAccessibleSelectionCountFromContext(long vmID, AccessibleSelection as);
BOOL IsAccessibleChildSelectedFromContext(long vmID, AccessibleSelection as, int i);
void RemoveAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
void SelectAllAccessibleSelectionFromContext(long vmID, AccessibleSelection as);
/**
* Additional methods for Teton
*/
/**
* Gets the AccessibleName for a component based upon the JAWS algorithm. Returns
* whether successful.
*
* Bug ID 4916682 - Implement JAWS AccessibleName policy
*/
BOOL getVirtualAccessibleName(const long vmID, const AccessibleContext accessibleContext,
wchar_t *name, int len);
/**
* Request focus for a component. Returns whether successful.
*
* Bug ID 4944757 - requestFocus method needed
*/
BOOL requestFocus(const long vmID, const AccessibleContext accessibleContext);
/**
* Selects text between two indices. Selection includes the text at the start index
* and the text at the end index. Returns whether successful.
*
* Bug ID 4944758 - selectTextRange method needed
*/
BOOL selectTextRange(const long vmID, const AccessibleContext accessibleContext, const int startIndex,
const int endIndex);
/**
* Get text attributes between two indices. The attribute list includes the text at the
* start index and the text at the end index. Returns whether successful;
*
* Bug ID 4944761 - getTextAttributes between two indices method needed
*/
BOOL getTextAttributesInRange(const long vmID, const AccessibleContext accessibleContext,
const int startIndex, const int endIndex,
AccessibleTextAttributesInfo *attributes, short *len);
/**
* Returns the number of visible children of a component. Returns -1 on error.
*
* Bug ID 4944762- getVisibleChildren for list-like components needed
*/
int getVisibleChildrenCount(const long vmID, const AccessibleContext accessibleContext);
/**
* Gets the visible children of an AccessibleContext. Returns whether successful.
*
* Bug ID 4944762- getVisibleChildren for list-like components needed
*/
BOOL getVisibleChildren(const long vmID, const AccessibleContext accessibleContext,
const int startIndex,
VisibleChildrenInfo *visibleChildrenInfo);
/**
* Set the caret to a text position. Returns whether successful.
*
* Bug ID 4944770 - setCaretPosition method needed
*/
BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext,
const int position);
/**
* Gets the text caret location
*/
BOOL getCaretLocation(long vmID, AccessibleContext ac,
AccessibleTextRectInfo *rectInfo, jint index);
/**
* Gets the number of events waiting to fire
*/
int getEventsWaiting();
#ifdef __cplusplus
}
#endif
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* Header file for packages of paramaters passed between Java Accessibility
* and native Assistive Technologies
*/
#ifndef __AccessBridgePackages_H__
#define __AccessBridgePackages_H__
#include <jni.h>
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ACCESSBRIDGE_ARCH_LEGACY
typedef jobject JOBJECT64;
typedef HWND ABHWND64;
#define ABHandleToLong
#define ABLongToHandle
#else
typedef jlong JOBJECT64;
typedef long ABHWND64;
#define ABHandleToLong HandleToLong
#define ABLongToHandle LongToHandle
#endif
#define MAX_BUFFER_SIZE 10240
#define MAX_STRING_SIZE 1024
#define SHORT_STRING_SIZE 256
// object types
typedef JOBJECT64 AccessibleContext;
typedef JOBJECT64 AccessibleText;
typedef JOBJECT64 AccessibleValue;
typedef JOBJECT64 AccessibleSelection;
typedef JOBJECT64 Java_Object;
typedef JOBJECT64 PropertyChangeEvent;
typedef JOBJECT64 FocusEvent;
typedef JOBJECT64 CaretEvent;
typedef JOBJECT64 MouseEvent;
typedef JOBJECT64 MenuEvent;
typedef JOBJECT64 AccessibleTable;
typedef JOBJECT64 AccessibleHyperlink;
typedef JOBJECT64 AccessibleHypertext;
/**
******************************************************
* Java event types
******************************************************
*/
#define cPropertyChangeEvent (jlong) 1 // 1
#define cFocusGainedEvent (jlong) 2 // 2
#define cFocusLostEvent (jlong) 4 // 4
#define cCaretUpdateEvent (jlong) 8 // 8
#define cMouseClickedEvent (jlong) 16 // 10
#define cMouseEnteredEvent (jlong) 32 // 20
#define cMouseExitedEvent (jlong) 64 // 40
#define cMousePressedEvent (jlong) 128 // 80
#define cMouseReleasedEvent (jlong) 256 // 100
#define cMenuCanceledEvent (jlong) 512 // 200
#define cMenuDeselectedEvent (jlong) 1024 // 400
#define cMenuSelectedEvent (jlong) 2048 // 800
#define cPopupMenuCanceledEvent (jlong) 4096 // 1000
#define cPopupMenuWillBecomeInvisibleEvent (jlong) 8192 // 2000
#define cPopupMenuWillBecomeVisibleEvent (jlong) 16384 // 4000
#define cJavaShutdownEvent (jlong) 32768 // 8000
/**
******************************************************
* Accessible Roles
* Defines all AccessibleRoles in Local.US
******************************************************
*/
/**
* Object is used to alert the user about something.
*/
#define ACCESSIBLE_ALERT L"alert"
/**
* The header for a column of data.
*/
#define ACCESSIBLE_COLUMN_HEADER L"column header"
/**
* Object that can be drawn into and is used to trap
* events.
* see ACCESSIBLE_FRAME
* see ACCESSIBLE_GLASS_PANE
* see ACCESSIBLE_LAYERED_PANE
*/
#define ACCESSIBLE_CANVAS L"canvas"
/**
* A list of choices the user can select from. Also optionally
* allows the user to enter a choice of their own.
*/
#define ACCESSIBLE_COMBO_BOX L"combo box"
/**
* An iconified internal frame in a DESKTOP_PANE.
* see ACCESSIBLE_DESKTOP_PANE
* see ACCESSIBLE_INTERNAL_FRAME
*/
#define ACCESSIBLE_DESKTOP_ICON L"desktop icon"
/**
* A frame-like object that is clipped by a desktop pane. The
* desktop pane, internal frame, and desktop icon objects are
* often used to create multiple document interfaces within an
* application.
* see ACCESSIBLE_DESKTOP_ICON
* see ACCESSIBLE_DESKTOP_PANE
* see ACCESSIBLE_FRAME
*/
#define ACCESSIBLE_INTERNAL_FRAME L"internal frame"
/**
* A pane that supports internal frames and
* iconified versions of those internal frames.
* see ACCESSIBLE_DESKTOP_ICON
* see ACCESSIBLE_INTERNAL_FRAME
*/
#define ACCESSIBLE_DESKTOP_PANE L"desktop pane"
/**
* A specialized pane whose primary use is inside a DIALOG
* see ACCESSIBLE_DIALOG
*/
#define ACCESSIBLE_OPTION_PANE L"option pane"
/**
* A top level window with no title or border.
* see ACCESSIBLE_FRAME
* see ACCESSIBLE_DIALOG
*/
#define ACCESSIBLE_WINDOW L"window"
/**
* A top level window with a title bar, border, menu bar, etc. It is
* often used as the primary window for an application.
* see ACCESSIBLE_DIALOG
* see ACCESSIBLE_CANVAS
* see ACCESSIBLE_WINDOW
*/
#define ACCESSIBLE_FRAME L"frame"
/**
* A top level window with title bar and a border. A dialog is similar
* to a frame, but it has fewer properties and is often used as a
* secondary window for an application.
* see ACCESSIBLE_FRAME
* see ACCESSIBLE_WINDOW
*/
#define ACCESSIBLE_DIALOG L"dialog"
/**
* A specialized dialog that lets the user choose a color.
*/
#define ACCESSIBLE_COLOR_CHOOSER L"color chooser"
/**
* A pane that allows the user to navigate through
* and select the contents of a directory. May be used
* by a file chooser.
* see ACCESSIBLE_FILE_CHOOSER
*/
#define ACCESSIBLE_DIRECTORY_PANE L"directory pane"
/**
* A specialized dialog that displays the files in the directory
* and lets the user select a file, browse a different directory,
* or specify a filename. May use the directory pane to show the
* contents of a directory.
* see ACCESSIBLE_DIRECTORY_PANE
*/
#define ACCESSIBLE_FILE_CHOOSER L"file chooser"
/**
* An object that fills up space in a user interface. It is often
* used in interfaces to tweak the spacing between components,
* but serves no other purpose.
*/
#define ACCESSIBLE_FILLER L"filler"
/**
* A hypertext anchor
*/
#define ACCESSIBLE_HYPERLINK L"hyperlink"
/**
* A small fixed size picture, typically used to decorate components.
*/
#define ACCESSIBLE_ICON L"icon"
/**
* An object used to present an icon or short string in an interface.
*/
#define ACCESSIBLE_LABEL L"label"
/**
* A specialized pane that has a glass pane and a layered pane as its
* children.
* see ACCESSIBLE_GLASS_PANE
* see ACCESSIBLE_LAYERED_PANE
*/
#define ACCESSIBLE_ROOT_PANE L"root pane"
/**
* A pane that is guaranteed to be painted on top
* of all panes beneath it.
* see ACCESSIBLE_ROOT_PANE
* see ACCESSIBLE_CANVAS
*/
#define ACCESSIBLE_GLASS_PANE L"glass pane"
/**
* A specialized pane that allows its children to be drawn in layers,
* providing a form of stacking order. This is usually the pane that
* holds the menu bar as well as the pane that contains most of the
* visual components in a window.
* see ACCESSIBLE_GLASS_PANE
* see ACCESSIBLE_ROOT_PANE
*/
#define ACCESSIBLE_LAYERED_PANE L"layered pane"
/**
* An object that presents a list of objects to the user and allows the
* user to select one or more of them. A list is usually contained
* within a scroll pane.
* see ACCESSIBLE_SCROLL_PANE
* see ACCESSIBLE_LIST_ITEM
*/
#define ACCESSIBLE_LIST L"list"
/**
* An object that presents an element in a list. A list is usually
* contained within a scroll pane.
* see ACCESSIBLE_SCROLL_PANE
* see ACCESSIBLE_LIST
*/
#define ACCESSIBLE_LIST_ITEM L"list item"
/**
* An object usually drawn at the top of the primary dialog box of
* an application that contains a list of menus the user can choose
* from. For example, a menu bar might contain menus for "File,"
* "Edit," and "Help."
* see ACCESSIBLE_MENU
* see ACCESSIBLE_POPUP_MENU
* see ACCESSIBLE_LAYERED_PANE
*/
#define ACCESSIBLE_MENU_BAR L"menu bar"
/**
* A temporary window that is usually used to offer the user a
* list of choices, and then hides when the user selects one of
* those choices.
* see ACCESSIBLE_MENU
* see ACCESSIBLE_MENU_ITEM
*/
#define ACCESSIBLE_POPUP_MENU L"popup menu"
/**
* An object usually found inside a menu bar that contains a list
* of actions the user can choose from. A menu can have any object
* as its children, but most often they are menu items, other menus,
* or rudimentary objects such as radio buttons, check boxes, or
* separators. For example, an application may have an "Edit" menu
* that contains menu items for "Cut" and "Paste."
* see ACCESSIBLE_MENU_BAR
* see ACCESSIBLE_MENU_ITEM
* see ACCESSIBLE_SEPARATOR
* see ACCESSIBLE_RADIO_BUTTON
* see ACCESSIBLE_CHECK_BOX
* see ACCESSIBLE_POPUP_MENU
*/
#define ACCESSIBLE_MENU L"menu"
/**
* An object usually contained in a menu that presents an action
* the user can choose. For example, the "Cut" menu item in an
* "Edit" menu would be an action the user can select to cut the
* selected area of text in a document.
* see ACCESSIBLE_MENU_BAR
* see ACCESSIBLE_SEPARATOR
* see ACCESSIBLE_POPUP_MENU
*/
#define ACCESSIBLE_MENU_ITEM L"menu item"
/**
* An object usually contained in a menu to provide a visual
* and logical separation of the contents in a menu. For example,
* the "File" menu of an application might contain menu items for
* "Open," "Close," and "Exit," and will place a separator between
* "Close" and "Exit" menu items.
* see ACCESSIBLE_MENU
* see ACCESSIBLE_MENU_ITEM
*/
#define ACCESSIBLE_SEPARATOR L"separator"
/**
* An object that presents a series of panels (or page tabs), one at a
* time, through some mechanism provided by the object. The most common
* mechanism is a list of tabs at the top of the panel. The children of
* a page tab list are all page tabs.
* see ACCESSIBLE_PAGE_TAB
*/
#define ACCESSIBLE_PAGE_TAB_LIST L"page tab list"
/**
* An object that is a child of a page tab list. Its sole child is
* the panel that is to be presented to the user when the user
* selects the page tab from the list of tabs in the page tab list.
* see ACCESSIBLE_PAGE_TAB_LIST
*/
#define ACCESSIBLE_PAGE_TAB L"page tab"
/**
* A generic container that is often used to group objects.
*/
#define ACCESSIBLE_PANEL L"panel"
/**
* An object used to indicate how much of a task has been completed.
*/
#define ACCESSIBLE_PROGRESS_BAR L"progress bar"
/**
* A text object used for passwords, or other places where the
* text contents is not shown visibly to the user
*/
#define ACCESSIBLE_PASSWORD_TEXT L"password text"
/**
* An object the user can manipulate to tell the application to do
* something.
* see ACCESSIBLE_CHECK_BOX
* see ACCESSIBLE_TOGGLE_BUTTON
* see ACCESSIBLE_RADIO_BUTTON
*/
#define ACCESSIBLE_PUSH_BUTTON L"push button"
/**
* A specialized push button that can be checked or unchecked, but
* does not provide a separate indicator for the current state.
* see ACCESSIBLE_PUSH_BUTTON
* see ACCESSIBLE_CHECK_BOX
* see ACCESSIBLE_RADIO_BUTTON
*/
#define ACCESSIBLE_TOGGLE_BUTTON L"toggle button"
/**
* A choice that can be checked or unchecked and provides a
* separate indicator for the current state.
* see ACCESSIBLE_PUSH_BUTTON
* see ACCESSIBLE_TOGGLE_BUTTON
* see ACCESSIBLE_RADIO_BUTTON
*/
#define ACCESSIBLE_CHECK_BOX L"check box"
/**
* A specialized check box that will cause other radio buttons in the
* same group to become unchecked when this one is checked.
* see ACCESSIBLE_PUSH_BUTTON
* see ACCESSIBLE_TOGGLE_BUTTON
* see ACCESSIBLE_CHECK_BOX
*/
#define ACCESSIBLE_RADIO_BUTTON L"radio button"
/**
* The header for a row of data.
*/
#define ACCESSIBLE_ROW_HEADER L"row header"
/**
* An object that allows a user to incrementally view a large amount
* of information. Its children can include scroll bars and a viewport.
* see ACCESSIBLE_SCROLL_BAR
* see ACCESSIBLE_VIEWPORT
*/
#define ACCESSIBLE_SCROLL_PANE L"scroll pane"
/**
* An object usually used to allow a user to incrementally view a
* large amount of data. Usually used only by a scroll pane.
* see ACCESSIBLE_SCROLL_PANE
*/
#define ACCESSIBLE_SCROLL_BAR L"scroll bar"
/**
* An object usually used in a scroll pane. It represents the portion
* of the entire data that the user can see. As the user manipulates
* the scroll bars, the contents of the viewport can change.
* see ACCESSIBLE_SCROLL_PANE
*/
#define ACCESSIBLE_VIEWPORT L"viewport"
/**
* An object that allows the user to select from a bounded range. For
* example, a slider might be used to select a number between 0 and 100.
*/
#define ACCESSIBLE_SLIDER L"slider"
/**
* A specialized panel that presents two other panels at the same time.
* Between the two panels is a divider the user can manipulate to make
* one panel larger and the other panel smaller.
*/
#define ACCESSIBLE_SPLIT_PANE L"split pane"
/**
* An object used to present information in terms of rows and columns.
* An example might include a spreadsheet application.
*/
#define ACCESSIBLE_TABLE L"table"
/**
* An object that presents text to the user. The text is usually
* editable by the user as opposed to a label.
* see ACCESSIBLE_LABEL
*/
#define ACCESSIBLE_TEXT L"text"
/**
* An object used to present hierarchical information to the user.
* The individual nodes in the tree can be collapsed and expanded
* to provide selective disclosure of the tree's contents.
*/
#define ACCESSIBLE_TREE L"tree"
/**
* A bar or palette usually composed of push buttons or toggle buttons.
* It is often used to provide the most frequently used functions for an
* application.
*/
#define ACCESSIBLE_TOOL_BAR L"tool bar"
/**
* An object that provides information about another object. The
* accessibleDescription property of the tool tip is often displayed
* to the user in a small L"help bubble" when the user causes the
* mouse to hover over the object associated with the tool tip.
*/
#define ACCESSIBLE_TOOL_TIP L"tool tip"
/**
* An AWT component, but nothing else is known about it.
* see ACCESSIBLE_SWING_COMPONENT
* see ACCESSIBLE_UNKNOWN
*/
#define ACCESSIBLE_AWT_COMPONENT L"awt component"
/**
* A Swing component, but nothing else is known about it.
* see ACCESSIBLE_AWT_COMPONENT
* see ACCESSIBLE_UNKNOWN
*/
#define ACCESSIBLE_SWING_COMPONENT L"swing component"
/**
* The object contains some Accessible information, but its role is
* not known.
* see ACCESSIBLE_AWT_COMPONENT
* see ACCESSIBLE_SWING_COMPONENT
*/
#define ACCESSIBLE_UNKNOWN L"unknown"
/**
* A STATUS_BAR is an simple component that can contain
* multiple labels of status information to the user.
*/
#define ACCESSIBLE_STATUS_BAR L"status bar"
/**
* A DATE_EDITOR is a component that allows users to edit
* java.util.Date and java.util.Time objects
*/
#define ACCESSIBLE_DATE_EDITOR L"date editor"
/**
* A SPIN_BOX is a simple spinner component and its main use
* is for simple numbers.
*/
#define ACCESSIBLE_SPIN_BOX L"spin box"
/**
* A FONT_CHOOSER is a component that lets the user pick various
* attributes for fonts.
*/
#define ACCESSIBLE_FONT_CHOOSER L"font chooser"
/**
* A GROUP_BOX is a simple container that contains a border
* around it and contains components inside it.
*/
#define ACCESSIBLE_GROUP_BOX L"group box"
/**
* A text header
*/
#define ACCESSIBLE_HEADER L"header"
/**
* A text footer
*/
#define ACCESSIBLE_FOOTER L"footer"
/**
* A text paragraph
*/
#define ACCESSIBLE_PARAGRAPH L"paragraph"
/**
* A ruler is an object used to measure distance
*/
#define ACCESSIBLE_RULER L"ruler"
/**
* A role indicating the object acts as a formula for
* calculating a value. An example is a formula in
* a spreadsheet cell.
*/
#define ACCESSIBLE_EDITBAR L"editbar"
/**
* A role indicating the object monitors the progress
* of some operation.
*/
#define PROGRESS_MONITOR L"progress monitor"
/**
******************************************************
* Accessibility event types
******************************************************
*/
#define cPropertyNameChangeEvent (jlong) 1 // 1
#define cPropertyDescriptionChangeEvent (jlong) 2 // 2
#define cPropertyStateChangeEvent (jlong) 4 // 4
#define cPropertyValueChangeEvent (jlong) 8 // 8
#define cPropertySelectionChangeEvent (jlong) 16 // 10
#define cPropertyTextChangeEvent (jlong) 32 // 20
#define cPropertyCaretChangeEvent (jlong) 64 // 40
#define cPropertyVisibleDataChangeEvent (jlong) 128 // 80
#define cPropertyChildChangeEvent (jlong) 256 // 100
#define cPropertyActiveDescendentChangeEvent (jlong) 512 // 200
#define cPropertyTableModelChangeEvent (jlong) 1024 // 400
/**
******************************************************
* optional AccessibleContext interfaces
*
* This version of the bridge reuses the accessibleValue
* field in the AccessibleContextInfo struct to represent
* additional optional interfaces that are supported by
* the Java AccessibleContext. This is backwardly compatable
* because the old accessibleValue was set to the BOOL
* value TRUE (i.e., 1) if the AccessibleValue interface is
* supported.
******************************************************
*/
#define cAccessibleValueInterface (jlong) 1 // 1 << 1 (TRUE)
#define cAccessibleActionInterface (jlong) 2 // 1 << 2
#define cAccessibleComponentInterface (jlong) 4 // 1 << 3
#define cAccessibleSelectionInterface (jlong) 8 // 1 << 4
#define cAccessibleTableInterface (jlong) 16 // 1 << 5
#define cAccessibleTextInterface (jlong) 32 // 1 << 6
#define cAccessibleHypertextInterface (jlong) 64 // 1 << 7
/**
******************************************************
* Accessibility information bundles
******************************************************
*/
typedef struct AccessBridgeVersionInfoTag {
wchar_t VMversion[SHORT_STRING_SIZE]; // output of "java -version"
wchar_t bridgeJavaClassVersion[SHORT_STRING_SIZE]; // version of the AccessBridge.class
wchar_t bridgeJavaDLLVersion[SHORT_STRING_SIZE]; // version of JavaAccessBridge.dll
wchar_t bridgeWinDLLVersion[SHORT_STRING_SIZE]; // version of WindowsAccessBridge.dll
} AccessBridgeVersionInfo;
typedef struct AccessibleContextInfoTag {
wchar_t name[MAX_STRING_SIZE]; // the AccessibleName of the object
wchar_t description[MAX_STRING_SIZE]; // the AccessibleDescription of the object
wchar_t role[SHORT_STRING_SIZE]; // localized AccesibleRole string
wchar_t role_en_US[SHORT_STRING_SIZE]; // AccesibleRole string in the en_US locale
wchar_t states[SHORT_STRING_SIZE]; // localized AccesibleStateSet string (comma separated)
wchar_t states_en_US[SHORT_STRING_SIZE]; // AccesibleStateSet string in the en_US locale (comma separated)
jint indexInParent; // index of object in parent
jint childrenCount; // # of children, if any
jint x; // screen coords in pixels
jint y; // "
jint width; // pixel width of object
jint height; // pixel height of object
BOOL accessibleComponent; // flags for various additional
BOOL accessibleAction; // Java Accessibility interfaces
BOOL accessibleSelection; // FALSE if this object doesn't
BOOL accessibleText; // implement the additional interface
// in question
// BOOL accessibleValue; // old BOOL indicating whether AccessibleValue is supported
BOOL accessibleInterfaces; // new bitfield containing additional interface flags
} AccessibleContextInfo;
// AccessibleText packages
typedef struct AccessibleTextInfoTag {
jint charCount; // # of characters in this text object
jint caretIndex; // index of caret
jint indexAtPoint; // index at the passsed in point
} AccessibleTextInfo;
typedef struct AccessibleTextItemsInfoTag {
wchar_t letter;
wchar_t word[SHORT_STRING_SIZE];
wchar_t sentence[MAX_STRING_SIZE];
} AccessibleTextItemsInfo;
typedef struct AccessibleTextSelectionInfoTag {
jint selectionStartIndex;
jint selectionEndIndex;
wchar_t selectedText[MAX_STRING_SIZE];
} AccessibleTextSelectionInfo;
typedef struct AccessibleTextRectInfoTag {
jint x; // bounding rect of char at index
jint y; // "
jint width; // "
jint height; // "
} AccessibleTextRectInfo;
// standard attributes for text; note: tabstops are not supported
typedef struct AccessibleTextAttributesInfoTag {
BOOL bold;
BOOL italic;
BOOL underline;
BOOL strikethrough;
BOOL superscript;
BOOL subscript;
wchar_t backgroundColor[SHORT_STRING_SIZE];
wchar_t foregroundColor[SHORT_STRING_SIZE];
wchar_t fontFamily[SHORT_STRING_SIZE];
jint fontSize;
jint alignment;
jint bidiLevel;
jfloat firstLineIndent;
jfloat leftIndent;
jfloat rightIndent;
jfloat lineSpacing;
jfloat spaceAbove;
jfloat spaceBelow;
wchar_t fullAttributesString[MAX_STRING_SIZE];
} AccessibleTextAttributesInfo;
/**
******************************************************
* IPC management typedefs
******************************************************
*/
#define cMemoryMappedNameSize 255
/**
* sent by the WindowsDLL -> the memory-mapped file is setup
*
*/
typedef struct MemoryMappedFileCreatedPackageTag {
// HWND bridgeWindow; // redundant, but easier to get to here...
ABHWND64 bridgeWindow; // redundant, but easier to get to here...
char filename[cMemoryMappedNameSize];
} MemoryMappedFileCreatedPackage;
/**
* sent when a new JavaVM attaches to the Bridge
*
*/
typedef struct JavaVMCreatedPackageTag {
ABHWND64 bridgeWindow;
long vmID;
} JavaVMCreatedPackage;
/**
* sent when a JavaVM detatches from the Bridge
*
*/
typedef struct JavaVMDestroyedPackageTag {
ABHWND64 bridgeWindow;
} JavaVMDestroyedPackage;
/**
* sent when a new AT attaches to the Bridge
*
*/
typedef struct WindowsATCreatedPackageTag {
ABHWND64 bridgeWindow;
} WindowsATCreatedPackage;
/**
* sent when an AT detatches from the Bridge
*
*/
typedef struct WindowsATDestroyedPackageTag {
ABHWND64 bridgeWindow;
} WindowsATDestroyedPackage;
/**
* sent by JVM Bridges in response to a WindowsATCreate
* message; saying "howdy, welcome to the neighborhood"
*
*/
typedef struct JavaVMPresentNotificationPackageTag {
ABHWND64 bridgeWindow;
long vmID;
} JavaVMPresentNotificationPackage;
/**
* sent by AT Bridges in response to a JavaVMCreate
* message; saying "howdy, welcome to the neighborhood"
*
*/
typedef struct WindowsATPresentNotificationPackageTag {
ABHWND64 bridgeWindow;
} WindowsATPresentNotificationPackage;
/**
******************************************************
* Core packages
******************************************************
*/
typedef struct ReleaseJavaObjectPackageTag {
long vmID;
JOBJECT64 object;
} ReleaseJavaObjectPackage;
typedef struct GetAccessBridgeVersionPackageTag {
long vmID; // can't get VM info w/out a VM!
AccessBridgeVersionInfo rVersionInfo;
} GetAccessBridgeVersionPackage;
typedef struct IsSameObjectPackageTag {
long vmID;
JOBJECT64 obj1;
JOBJECT64 obj2;
jboolean rResult;
} IsSameObjectPackage;
/**
******************************************************
* Windows packages
******************************************************
*/
typedef struct IsJavaWindowPackageTag {
jint window;
jboolean rResult;
} IsJavaWindowPackage;
typedef struct GetAccessibleContextFromHWNDPackageTag {
jint window;
long rVMID;
JOBJECT64 rAccessibleContext;
} GetAccessibleContextFromHWNDPackage;
typedef struct GetHWNDFromAccessibleContextPackageTag {
JOBJECT64 accessibleContext;
ABHWND64 rHWND;
} GetHWNDFromAccessibleContextPackage;
/**
******************************************************
* AccessibleContext packages
******************************************************
*/
typedef struct GetAccessibleContextAtPackageTag {
jint x;
jint y;
long vmID;
JOBJECT64 AccessibleContext; // look within this AC
JOBJECT64 rAccessibleContext;
} GetAccessibleContextAtPackage;
typedef struct GetAccessibleContextWithFocusPackageTag {
long rVMID;
JOBJECT64 rAccessibleContext;
} GetAccessibleContextWithFocusPackage;
typedef struct GetAccessibleContextInfoPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
AccessibleContextInfo rAccessibleContextInfo;
} GetAccessibleContextInfoPackage;
typedef struct GetAccessibleChildFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint childIndex;
JOBJECT64 rAccessibleContext;
} GetAccessibleChildFromContextPackage;
typedef struct GetAccessibleParentFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
JOBJECT64 rAccessibleContext;
} GetAccessibleParentFromContextPackage;
/**
******************************************************
* AccessibleTable packages
******************************************************
*/
#define MAX_TABLE_SELECTIONS 64
// table information
typedef struct AccessibleTableInfoTag {
JOBJECT64 caption; // AccesibleContext
JOBJECT64 summary; // AccessibleContext
jint rowCount;
jint columnCount;
JOBJECT64 accessibleContext;
JOBJECT64 accessibleTable;
} AccessibleTableInfo;
typedef struct GetAccessibleTableInfoPackageTag {
long vmID;
JOBJECT64 accessibleContext;
AccessibleTableInfo rTableInfo;
} GetAccessibleTableInfoPackage;
// table cell information
typedef struct AccessibleTableCellInfoTag {
JOBJECT64 accessibleContext;
jint index;
jint row;
jint column;
jint rowExtent;
jint columnExtent;
jboolean isSelected;
} AccessibleTableCellInfo;
typedef struct GetAccessibleTableCellInfoPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint row;
jint column;
AccessibleTableCellInfo rTableCellInfo;
} GetAccessibleTableCellInfoPackage;
typedef struct GetAccessibleTableRowHeaderPackageTag {
long vmID;
JOBJECT64 accessibleContext;
AccessibleTableInfo rTableInfo;
} GetAccessibleTableRowHeaderPackage;
typedef struct GetAccessibleTableColumnHeaderPackageTag {
long vmID;
JOBJECT64 accessibleContext;
AccessibleTableInfo rTableInfo;
} GetAccessibleTableColumnHeaderPackage;
typedef struct GetAccessibleTableRowDescriptionPackageTag {
long vmID;
JOBJECT64 accessibleContext;
jint row;
JOBJECT64 rAccessibleContext;
} GetAccessibleTableRowDescriptionPackage;
typedef struct GetAccessibleTableColumnDescriptionPackageTag {
long vmID;
JOBJECT64 accessibleContext;
jint column;
JOBJECT64 rAccessibleContext;
} GetAccessibleTableColumnDescriptionPackage;
typedef struct GetAccessibleTableRowSelectionCountPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint rCount;
} GetAccessibleTableRowSelectionCountPackage;
typedef struct IsAccessibleTableRowSelectedPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint row;
jboolean rResult;
} IsAccessibleTableRowSelectedPackage;
typedef struct GetAccessibleTableRowSelectionsPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint count;
jint rSelections[MAX_TABLE_SELECTIONS];
} GetAccessibleTableRowSelectionsPackage;
typedef struct GetAccessibleTableColumnSelectionCountPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint rCount;
} GetAccessibleTableColumnSelectionCountPackage;
typedef struct IsAccessibleTableColumnSelectedPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint column;
jboolean rResult;
} IsAccessibleTableColumnSelectedPackage;
typedef struct GetAccessibleTableColumnSelectionsPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint count;
jint rSelections[MAX_TABLE_SELECTIONS];
} GetAccessibleTableColumnSelectionsPackage;
typedef struct GetAccessibleTableRowPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint index;
jint rRow;
} GetAccessibleTableRowPackage;
typedef struct GetAccessibleTableColumnPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint index;
jint rColumn;
} GetAccessibleTableColumnPackage;
typedef struct GetAccessibleTableIndexPackageTag {
long vmID;
JOBJECT64 accessibleTable;
jint row;
jint column;
jint rIndex;
} GetAccessibleTableIndexPackage;
/**
******************************************************
* AccessibleRelationSet packages
******************************************************
*/
#define MAX_RELATION_TARGETS 25
#define MAX_RELATIONS 5
typedef struct AccessibleRelationInfoTag {
wchar_t key[SHORT_STRING_SIZE];
jint targetCount;
JOBJECT64 targets[MAX_RELATION_TARGETS]; // AccessibleContexts
} AccessibleRelationInfo;
typedef struct AccessibleRelationSetInfoTag {
jint relationCount;
AccessibleRelationInfo relations[MAX_RELATIONS];
} AccessibleRelationSetInfo;
typedef struct GetAccessibleRelationSetPackageTag {
long vmID;
JOBJECT64 accessibleContext;
AccessibleRelationSetInfo rAccessibleRelationSetInfo;
} GetAccessibleRelationSetPackage;
/**
******************************************************
* AccessibleHypertext packagess
******************************************************
*/
#define MAX_HYPERLINKS 64 // maximum number of hyperlinks returned
// hyperlink information
typedef struct AccessibleHyperlinkInfoTag {
wchar_t text[SHORT_STRING_SIZE]; // the hyperlink text
jint startIndex; //index in the hypertext document where the link begins
jint endIndex; //index in the hypertext document where the link ends
JOBJECT64 accessibleHyperlink; // AccessibleHyperlink object
} AccessibleHyperlinkInfo;
// hypertext information
typedef struct AccessibleHypertextInfoTag {
jint linkCount; // number of hyperlinks
AccessibleHyperlinkInfo links[MAX_HYPERLINKS]; // the hyperlinks
JOBJECT64 accessibleHypertext; // AccessibleHypertext object
} AccessibleHypertextInfo;
// struct for sending a message to get the hypertext for an AccessibleContext
typedef struct GetAccessibleHypertextPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 accessibleContext; // AccessibleContext with hypertext
AccessibleHypertextInfo rAccessibleHypertextInfo; // returned hypertext
} GetAccessibleHypertextPackage;
// struct for sending an message to activate a hyperlink
typedef struct ActivateAccessibleHyperlinkPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 accessibleContext; // AccessibleContext containing the link
JOBJECT64 accessibleHyperlink; // the link to activate
BOOL rResult; // hyperlink activation return value
} ActivateAccessibleHyperlinkPackage;
// struct for sending a message to get the number of hyperlinks in a component
typedef struct GetAccessibleHyperlinkCountPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 accessibleContext; // AccessibleContext containing AccessibleHypertext
jint rLinkCount; // link count return value
} GetAccessibleHyperlinkCountPackage;
// struct for sending a message to get the hypertext for an AccessibleContext
// starting at a specified index in the document
typedef struct GetAccessibleHypertextExtPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 accessibleContext; // AccessibleContext with hypertext
jint startIndex; // start index in document
AccessibleHypertextInfo rAccessibleHypertextInfo; // returned hypertext
BOOL rSuccess; // whether call succeeded
} GetAccessibleHypertextExtPackage;
// struct for sending a message to get the nth hyperlink in a document;
// maps to AccessibleHypertext.getLink
typedef struct GetAccessibleHyperlinkPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 hypertext; // AccessibleHypertext
jint linkIndex; // hyperlink index
AccessibleHyperlinkInfo rAccessibleHyperlinkInfo; // returned hyperlink
} GetAccessibleHyperlinkPackage;
// struct for sending a message to get the index into an array
// of hyperlinks that is associated with a character index in a
// document; maps to AccessibleHypertext.getLinkIndex
typedef struct GetAccessibleHypertextLinkIndexPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 hypertext; // AccessibleHypertext
jint charIndex; // character index in document
jint rLinkIndex; // returned hyperlink index
} GetAccessibleHypertextLinkIndexPackage;
/**
******************************************************
* Accessible Key Bindings packages
******************************************************
*/
#define MAX_KEY_BINDINGS 10
// keyboard character modifiers
#define ACCESSIBLE_SHIFT_KEYSTROKE 1
#define ACCESSIBLE_CONTROL_KEYSTROKE 2
#define ACCESSIBLE_META_KEYSTROKE 4
#define ACCESSIBLE_ALT_KEYSTROKE 8
#define ACCESSIBLE_ALT_GRAPH_KEYSTROKE 16
#define ACCESSIBLE_BUTTON1_KEYSTROKE 32
#define ACCESSIBLE_BUTTON2_KEYSTROKE 64
#define ACCESSIBLE_BUTTON3_KEYSTROKE 128
#define ACCESSIBLE_FKEY_KEYSTROKE 256 // F key pressed, character contains 1-24
#define ACCESSIBLE_CONTROLCODE_KEYSTROKE 512 // Control code key pressed, character contains control code.
// The supported control code keys are:
#define ACCESSIBLE_VK_BACK_SPACE 8
#define ACCESSIBLE_VK_DELETE 127
#define ACCESSIBLE_VK_DOWN 40
#define ACCESSIBLE_VK_END 35
#define ACCESSIBLE_VK_HOME 36
#define ACCESSIBLE_VK_INSERT 155
#define ACCESSIBLE_VK_KP_DOWN 225
#define ACCESSIBLE_VK_KP_LEFT 226
#define ACCESSIBLE_VK_KP_RIGHT 227
#define ACCESSIBLE_VK_KP_UP 224
#define ACCESSIBLE_VK_LEFT 37
#define ACCESSIBLE_VK_PAGE_DOWN 34
#define ACCESSIBLE_VK_PAGE_UP 33
#define ACCESSIBLE_VK_RIGHT 39
#define ACCESSIBLE_VK_UP 38
// a key binding associates with a component
typedef struct AccessibleKeyBindingInfoTag {
jchar character; // the key character
jint modifiers; // the key modifiers
} AccessibleKeyBindingInfo;
// all of the key bindings associated with a component
typedef struct AccessibleKeyBindingsTag {
int keyBindingsCount; // number of key bindings
AccessibleKeyBindingInfo keyBindingInfo[MAX_KEY_BINDINGS];
} AccessibleKeyBindings;
// struct to get the key bindings associated with a component
typedef struct GetAccessibleKeyBindingsPackageTag {
long vmID; // the virtual machine id
JOBJECT64 accessibleContext; // the component
AccessibleKeyBindings rAccessibleKeyBindings; // the key bindings
} GetAccessibleKeyBindingsPackage;
/**
******************************************************
* AccessibleIcon packages
******************************************************
*/
#define MAX_ICON_INFO 8
// an icon assocated with a component
typedef struct AccessibleIconInfoTag {
wchar_t description[SHORT_STRING_SIZE]; // icon description
jint height; // icon height
jint width; // icon width
} AccessibleIconInfo;
// all of the icons associated with a component
typedef struct AccessibleIconsTag {
jint iconsCount; // number of icons
AccessibleIconInfo iconInfo[MAX_ICON_INFO]; // the icons
} AccessibleIcons;
// struct to get the icons associated with a component
typedef struct GetAccessibleIconsPackageTag {
long vmID; // the virtual machine id
JOBJECT64 accessibleContext; // the component
AccessibleIcons rAccessibleIcons; // the icons
} GetAccessibleIconsPackage;
/**
******************************************************
* AccessibleAction packages
******************************************************
*/
#define MAX_ACTION_INFO 256
#define MAX_ACTIONS_TO_DO 32
// an action assocated with a component
typedef struct AccessibleActionInfoTag {
wchar_t name[SHORT_STRING_SIZE]; // action name
} AccessibleActionInfo;
// all of the actions associated with a component
typedef struct AccessibleActionsTag {
jint actionsCount; // number of actions
AccessibleActionInfo actionInfo[MAX_ACTION_INFO]; // the action information
} AccessibleActions;
// struct for requesting the actions associated with a component
typedef struct GetAccessibleActionsPackageTag {
long vmID;
JOBJECT64 accessibleContext; // the component
AccessibleActions rAccessibleActions; // the actions
} GetAccessibleActionsPackage;
// list of AccessibleActions to do
typedef struct AccessibleActionsToDoTag {
jint actionsCount; // number of actions to do
AccessibleActionInfo actions[MAX_ACTIONS_TO_DO];// the accessible actions to do
} AccessibleActionsToDo;
// struct for sending an message to do one or more actions
typedef struct DoAccessibleActionsPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 accessibleContext; // component to do the action
AccessibleActionsToDo actionsToDo; // the accessible actions to do
BOOL rResult; // action return value
jint failure; // index of action that failed if rResult is FALSE
} DoAccessibleActionsPackage;
/**
******************************************************
* AccessibleText packages
******************************************************
*/
typedef struct GetAccessibleTextInfoPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint x;
jint y;
AccessibleTextInfo rTextInfo;
} GetAccessibleTextInfoPackage;
typedef struct GetAccessibleTextItemsPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
AccessibleTextItemsInfo rTextItemsInfo;
} GetAccessibleTextItemsPackage;
typedef struct GetAccessibleTextSelectionInfoPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
AccessibleTextSelectionInfo rTextSelectionItemsInfo;
} GetAccessibleTextSelectionInfoPackage;
typedef struct GetAccessibleTextAttributeInfoPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
AccessibleTextAttributesInfo rAttributeInfo;
} GetAccessibleTextAttributeInfoPackage;
typedef struct GetAccessibleTextRectInfoPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
AccessibleTextRectInfo rTextRectInfo;
} GetAccessibleTextRectInfoPackage;
typedef struct GetCaretLocationPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
AccessibleTextRectInfo rTextRectInfo;
} GetCaretLocationPackage;
typedef struct GetAccessibleTextLineBoundsPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
jint rLineStart;
jint rLineEnd;
} GetAccessibleTextLineBoundsPackage;
typedef struct GetAccessibleTextRangePackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint start;
jint end;
wchar_t rText[MAX_BUFFER_SIZE];
} GetAccessibleTextRangePackage;
/**
******************************************************
*
* Utility method packages
******************************************************
*/
typedef struct SetTextContentsPackageTag {
long vmID;
JOBJECT64 accessibleContext; // the text field
wchar_t text[MAX_STRING_SIZE]; // the text
BOOL rResult;
} SetTextContentsPackage;
typedef struct GetParentWithRolePackageTag {
long vmID;
JOBJECT64 accessibleContext;
wchar_t role[SHORT_STRING_SIZE]; // one of Accessible Roles above
JOBJECT64 rAccessibleContext;
} GetParentWithRolePackage;
typedef struct GetTopLevelObjectPackageTag {
long vmID;
JOBJECT64 accessibleContext;
JOBJECT64 rAccessibleContext;
} GetTopLevelObjectPackage;
typedef struct GetParentWithRoleElseRootPackageTag {
long vmID;
JOBJECT64 accessibleContext;
wchar_t role[SHORT_STRING_SIZE]; // one of Accessible Roles above
JOBJECT64 rAccessibleContext;
} GetParentWithRoleElseRootPackage;
typedef struct GetObjectDepthPackageTag {
long vmID;
JOBJECT64 accessibleContext;
jint rResult;
} GetObjectDepthPackage;
typedef struct GetActiveDescendentPackageTag {
long vmID;
JOBJECT64 accessibleContext;
JOBJECT64 rAccessibleContext;
} GetActiveDescendentPackage;
/**
******************************************************
* AccessibleValue packages
******************************************************
*/
typedef struct GetCurrentAccessibleValueFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
wchar_t rValue[SHORT_STRING_SIZE];
} GetCurrentAccessibleValueFromContextPackage;
typedef struct GetMaximumAccessibleValueFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
wchar_t rValue[SHORT_STRING_SIZE];
} GetMaximumAccessibleValueFromContextPackage;
typedef struct GetMinimumAccessibleValueFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
wchar_t rValue[SHORT_STRING_SIZE];
} GetMinimumAccessibleValueFromContextPackage;
/**
******************************************************
* AccessibleSelection packages
******************************************************
*/
typedef struct AddAccessibleSelectionFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
} AddAccessibleSelectionFromContextPackage;
typedef struct ClearAccessibleSelectionFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
} ClearAccessibleSelectionFromContextPackage;
typedef struct GetAccessibleSelectionFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
JOBJECT64 rAccessibleContext;
} GetAccessibleSelectionFromContextPackage;
typedef struct GetAccessibleSelectionCountFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint rCount;
} GetAccessibleSelectionCountFromContextPackage;
typedef struct IsAccessibleChildSelectedFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
jboolean rResult;
} IsAccessibleChildSelectedFromContextPackage;
typedef struct RemoveAccessibleSelectionFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
jint index;
} RemoveAccessibleSelectionFromContextPackage;
typedef struct SelectAllAccessibleSelectionFromContextPackageTag {
long vmID;
JOBJECT64 AccessibleContext;
} SelectAllAccessibleSelectionFromContextPackage;
/**
******************************************************
* Java Event Notification Registration packages
******************************************************
*/
typedef struct AddJavaEventNotificationPackageTag {
jlong type;
//HWND DLLwindow;
ABHWND64 DLLwindow;
} AddJavaEventNotificationPackage;
typedef struct RemoveJavaEventNotificationPackageTag {
jlong type;
//HWND DLLwindow;
ABHWND64 DLLwindow;
} RemoveJavaEventNotificationPackage;
/**
******************************************************
* Accessibility Event Notification Registration packages
******************************************************
*/
typedef struct AddAccessibilityEventNotificationPackageTag {
jlong type;
//HWND DLLwindow;
ABHWND64 DLLwindow;
} AddAccessibilityEventNotificationPackage;
typedef struct RemoveAccessibilityEventNotificationPackageTag {
jlong type;
//HWND DLLwindow;
ABHWND64 DLLwindow;
} RemoveAccessibilityEventNotificationPackage;
/**
******************************************************
* Accessibility Property Change Event packages
******************************************************
*/
typedef struct PropertyCaretChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
jint oldPosition;
jint newPosition;
} PropertyCaretChangePackage;
typedef struct PropertyDescriptionChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
wchar_t oldDescription[SHORT_STRING_SIZE];
wchar_t newDescription[SHORT_STRING_SIZE];
} PropertyDescriptionChangePackage;
typedef struct PropertyNameChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
wchar_t oldName[SHORT_STRING_SIZE];
wchar_t newName[SHORT_STRING_SIZE];
} PropertyNameChangePackage;
typedef struct PropertySelectionChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} PropertySelectionChangePackage;
typedef struct PropertyStateChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
wchar_t oldState[SHORT_STRING_SIZE];
wchar_t newState[SHORT_STRING_SIZE];
} PropertyStateChangePackage;
typedef struct PropertyTextChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} PropertyTextChangePackage;
typedef struct PropertyValueChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
wchar_t oldValue[SHORT_STRING_SIZE];
wchar_t newValue[SHORT_STRING_SIZE];
} PropertyValueChangePackage;
typedef struct PropertyVisibleDataChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} PropertyVisibleDataChangePackage;
typedef struct PropertyChildChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
JOBJECT64 oldChildAccessibleContext;
JOBJECT64 newChildAccessibleContext;
} PropertyChildChangePackage;
typedef struct PropertyActiveDescendentChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
JOBJECT64 oldActiveDescendentAccessibleContext;
JOBJECT64 newActiveDescendentAccessibleContext;
} PropertyActiveDescendentChangePackage;
// String format for newValue is:
// "type" one of "INSERT", "UPDATE" or "DELETE"
// "firstRow"
// "lastRow"
// "firstColumn"
// "lastColumn"
//
// oldValue is currently unused
//
typedef struct PropertyTableModelChangePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
wchar_t oldValue[SHORT_STRING_SIZE];
wchar_t newValue[SHORT_STRING_SIZE];
} PropertyTableModelChangePackage;
/**
******************************************************
* Property Change Event packages
******************************************************
*/
/*
typedef struct PropertyChangePackageTag {
long vmID;
jobject Event;
jobject AccessibleContextSource;
char propertyName[SHORT_STRING_SIZE];
char oldValue[SHORT_STRING_SIZE]; // PropertyChangeEvent().getOldValue().toString()
char newValue[SHORT_STRING_SIZE]; // PropertyChangeEvent().getNewValue().toString()
} PropertyChangePackage;
*/
/*
* Java shutdown event package
*/
typedef struct JavaShutdownPackageTag {
long vmID;
} JavaShutdownPackage;
/**
******************************************************
* Focus Event packages
******************************************************
*/
typedef struct FocusGainedPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} FocusGainedPackage;
typedef struct FocusLostPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} FocusLostPackage;
/**
******************************************************
* Caret Event packages
******************************************************
*/
typedef struct CaretUpdatePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} CaretUpdatePackage;
/**
******************************************************
* Mouse Event packages
******************************************************
*/
typedef struct MouseClickedPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} MouseClickedPackage;
typedef struct MouseEnteredPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} MouseEnteredPackage;
typedef struct MouseExitedPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} MouseExitedPackage;
typedef struct MousePressedPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} MousePressedPackage;
typedef struct MouseReleasedPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} MouseReleasedPackage;
/**
******************************************************
* Menu/PopupMenu Event packages
******************************************************
*/
typedef struct MenuCanceledPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} MenuCanceledPackage;
typedef struct MenuDeselectedPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} MenuDeselectedPackage;
typedef struct MenuSelectedPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} MenuSelectedPackage;
typedef struct PopupMenuCanceledPackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} PopupMenuCanceledPackage;
typedef struct PopupMenuWillBecomeInvisiblePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} PopupMenuWillBecomeInvisiblePackage;
typedef struct PopupMenuWillBecomeVisiblePackageTag {
long vmID;
JOBJECT64 Event;
JOBJECT64 AccessibleContextSource;
} PopupMenuWillBecomeVisiblePackage;
/**
******************************************************
* Additional methods for Teton
******************************************************
*/
/**
* Gets the AccessibleName for a component based upon the JAWS algorithm. Returns
* whether successful.
*
* Bug ID 4916682 - Implement JAWS AccessibleName policy
*/
typedef struct GetVirtualAccessibleNamePackageTag {
long vmID;
AccessibleContext accessibleContext;
wchar_t rName[MAX_STRING_SIZE];
int len;
} GetVirtualAccessibleNamePackage;
/**
* Request focus for a component. Returns whether successful;
*
* Bug ID 4944757 - requestFocus method needed
*/
typedef struct RequestFocusPackageTag {
long vmID;
AccessibleContext accessibleContext;
} RequestFocusPackage;
/**
* Selects text between two indices. Selection includes the text at the start index
* and the text at the end index. Returns whether successful;
*
* Bug ID 4944758 - selectTextRange method needed
*/
typedef struct SelectTextRangePackageTag {
long vmID;
AccessibleContext accessibleContext;
jint startIndex;
jint endIndex;
} SelectTextRangePackage;
/**
* Gets the number of contiguous characters with the same attributes.
*
* Bug ID 4944761 - getTextAttributes between two indices method needed
*/
typedef struct GetTextAttributesInRangePackageTag {
long vmID;
AccessibleContext accessibleContext;
jint startIndex; // start index (inclusive)
jint endIndex; // end index (inclusive)
AccessibleTextAttributesInfo attributes; // character attributes to match
short rLength; // number of contiguous characters with matching attributes
} GetTextAttributesInRangePackage;
#define MAX_VISIBLE_CHILDREN 256
// visible children information
typedef struct VisibleChildenInfoTag {
int returnedChildrenCount; // number of children returned
AccessibleContext children[MAX_VISIBLE_CHILDREN]; // the visible children
} VisibleChildrenInfo;
// struct for sending a message to get the number of visible children
typedef struct GetVisibleChildrenCountPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 accessibleContext; // AccessibleContext of parent component
jint rChildrenCount; // visible children count return value
} GetVisibleChildrenCountPackage;
// struct for sending a message to get the hypertext for an AccessibleContext
// starting at a specified index in the document
typedef struct GetVisibleChildrenPackageTag {
long vmID; // the virtual machine ID
JOBJECT64 accessibleContext; // AccessibleContext of parent component
jint startIndex; // start index for retrieving children
VisibleChildrenInfo rVisibleChildrenInfo; // returned info
BOOL rSuccess; // whether call succeeded
} GetVisibleChildrenPackage;
/**
* Set the caret to a text position. Returns whether successful;
*
* Bug ID 4944770 - setCaretPosition method needed
*/
typedef struct SetCaretPositionPackageTag {
long vmID;
AccessibleContext accessibleContext;
jint position;
} SetCaretPositionPackage;
/**
******************************************************
* Wrapping up all of the packages
******************************************************
*/
/**
* What is the type of this package
*/
typedef enum PackageType {
cMemoryMappedFileCreatedPackage = 0x11000,
// many of these will go away...
cJavaVMCreatedPackage = 0x10000,
cJavaVMDestroyedPackage,
cWindowsATCreatedPackage,
cWindowsATDestroyedPackage,
cJavaVMPresentNotificationPackage,
cWindowsATPresentNotificationPackage,
cReleaseJavaObjectPackage = 1,
cGetAccessBridgeVersionPackage = 2,
cGetAccessibleContextFromHWNDPackage = 0x10,
cIsJavaWindowPackage,
cGetHWNDFromAccessibleContextPackage,
cGetAccessibleContextAtPackage = 0x100,
cGetAccessibleContextWithFocusPackage,
cGetAccessibleContextInfoPackage,
cGetAccessibleChildFromContextPackage,
cGetAccessibleParentFromContextPackage,
cIsSameObjectPackage,
cGetAccessibleTextInfoPackage = 0x200,
cGetAccessibleTextItemsPackage,
cGetAccessibleTextSelectionInfoPackage,
cGetAccessibleTextAttributeInfoPackage,
cGetAccessibleTextRectInfoPackage,
cGetAccessibleTextLineBoundsPackage,
cGetAccessibleTextRangePackage,
cGetCurrentAccessibleValueFromContextPackage = 0x300,
cGetMaximumAccessibleValueFromContextPackage,
cGetMinimumAccessibleValueFromContextPackage,
cAddAccessibleSelectionFromContextPackage = 0x400,
cClearAccessibleSelectionFromContextPackage,
cGetAccessibleSelectionFromContextPackage,
cGetAccessibleSelectionCountFromContextPackage,
cIsAccessibleChildSelectedFromContextPackage,
cRemoveAccessibleSelectionFromContextPackage,
cSelectAllAccessibleSelectionFromContextPackage,
cAddJavaEventNotificationPackage = 0x900,
cRemoveJavaEventNotificationPackage,
cAddAccessibilityEventNotificationPackage,
cRemoveAccessibilityEventNotificationPackage,
cPropertyChangePackage = 0x1000,
cJavaShutdownPackage = 0x1010,
cFocusGainedPackage,
cFocusLostPackage,
cCaretUpdatePackage = 0x1020,
cMouseClickedPackage = 0x1030,
cMouseEnteredPackage,
cMouseExitedPackage,
cMousePressedPackage,
cMouseReleasedPackage,
cMenuCanceledPackage = 0x1040,
cMenuDeselectedPackage,
cMenuSelectedPackage,
cPopupMenuCanceledPackage,
cPopupMenuWillBecomeInvisiblePackage,
cPopupMenuWillBecomeVisiblePackage,
cPropertyCaretChangePackage = 0x1100,
cPropertyDescriptionChangePackage,
cPropertyNameChangePackage,
cPropertySelectionChangePackage,
cPropertyStateChangePackage,
cPropertyTextChangePackage,
cPropertyValueChangePackage,
cPropertyVisibleDataChangePackage,
cPropertyChildChangePackage,
cPropertyActiveDescendentChangePackage,
// AccessibleTable
cGetAccessibleTableInfoPackage = 0x1200,
cGetAccessibleTableCellInfoPackage,
cGetAccessibleTableRowHeaderPackage,
cGetAccessibleTableColumnHeaderPackage,
cGetAccessibleTableRowDescriptionPackage,
cGetAccessibleTableColumnDescriptionPackage,
cGetAccessibleTableRowSelectionCountPackage,
cIsAccessibleTableRowSelectedPackage,
cGetAccessibleTableRowSelectionsPackage,
cGetAccessibleTableColumnSelectionCountPackage,
cIsAccessibleTableColumnSelectedPackage,
cGetAccessibleTableColumnSelectionsPackage,
cGetAccessibleTableRowPackage,
cGetAccessibleTableColumnPackage,
cGetAccessibleTableIndexPackage,
cPropertyTableModelChangePackage,
// AccessibleRelationSet
cGetAccessibleRelationSetPackage = 0x1300,
// AccessibleHypertext
cGetAccessibleHypertextPackage = 0x1400,
cActivateAccessibleHyperlinkPackage,
cGetAccessibleHyperlinkCountPackage,
cGetAccessibleHypertextExtPackage,
cGetAccessibleHypertextLinkIndexPackage,
cGetAccessibleHyperlinkPackage,
// Accessible KeyBinding, Icon and Action
cGetAccessibleKeyBindingsPackage = 0x1500,
cGetAccessibleIconsPackage,
cGetAccessibleActionsPackage,
cDoAccessibleActionsPackage,
// Utility methods
cSetTextContentsPackage = 0x1600,
cGetParentWithRolePackage,
cGetTopLevelObjectPackage,
cGetParentWithRoleElseRootPackage,
cGetObjectDepthPackage,
cGetActiveDescendentPackage,
// Additional methods for Teton
cGetVirtualAccessibleNamePackage = 0x1700,
cRequestFocusPackage,
cSelectTextRangePackage,
cGetTextAttributesInRangePackage,
cGetSameTextAttributesInRangePackage,
cGetVisibleChildrenCountPackage,
cGetVisibleChildrenPackage,
cSetCaretPositionPackage,
cGetCaretLocationPackage
} PackageType;
/**
* Union of all package contents
*/
typedef union AllPackagesTag {
// Initial Rendezvous packages
MemoryMappedFileCreatedPackage memoryMappedFileCreatedPackage;
JavaVMCreatedPackage javaVMCreatedPackage;
JavaVMDestroyedPackage javaVMDestroyedPackage;
WindowsATCreatedPackage windowsATCreatedPackage;
WindowsATDestroyedPackage windowsATDestroyedPackage;
JavaVMPresentNotificationPackage javaVMPresentNotificationPackage;
WindowsATPresentNotificationPackage windowsATPresentNotificationPackage;
// Core packages
ReleaseJavaObjectPackage releaseJavaObject;
GetAccessBridgeVersionPackage getAccessBridgeVersion;
// Window packages
GetAccessibleContextFromHWNDPackage getAccessibleContextFromHWND;
GetHWNDFromAccessibleContextPackage getHWNDFromAccessibleContext;
// AccessibleContext packages
GetAccessibleContextAtPackage getAccessibleContextAt;
GetAccessibleContextWithFocusPackage getAccessibleContextWithFocus;
GetAccessibleContextInfoPackage getAccessibleContextInfo;
GetAccessibleChildFromContextPackage getAccessibleChildFromContext;
GetAccessibleParentFromContextPackage getAccessibleParentFromContext;
// AccessibleText packages
GetAccessibleTextInfoPackage getAccessibleTextInfo;
GetAccessibleTextItemsPackage getAccessibleTextItems;
GetAccessibleTextSelectionInfoPackage getAccessibleTextSelectionInfo;
GetAccessibleTextAttributeInfoPackage getAccessibleTextAttributeInfo;
GetAccessibleTextRectInfoPackage getAccessibleTextRectInfo;
GetAccessibleTextLineBoundsPackage getAccessibleTextLineBounds;
GetAccessibleTextRangePackage getAccessibleTextRange;
// AccessibleValue packages
GetCurrentAccessibleValueFromContextPackage getCurrentAccessibleValueFromContext;
GetMaximumAccessibleValueFromContextPackage getMaximumAccessibleValueFromContext;
GetMinimumAccessibleValueFromContextPackage getMinimumAccessibleValueFromContext;
// AccessibleSelection packages
AddAccessibleSelectionFromContextPackage addAccessibleSelectionFromContext;
ClearAccessibleSelectionFromContextPackage clearAccessibleSelectionFromContext;
GetAccessibleSelectionFromContextPackage getAccessibleSelectionFromContext;
GetAccessibleSelectionCountFromContextPackage getAccessibleSelectionCountFromContext;
IsAccessibleChildSelectedFromContextPackage isAccessibleChildSelectedFromContext;
RemoveAccessibleSelectionFromContextPackage removeAccessibleSelectionFromContext;
SelectAllAccessibleSelectionFromContextPackage selectAllAccessibleSelectionFromContext;
// Event Notification Registration packages
AddJavaEventNotificationPackage addJavaEventNotification;
RemoveJavaEventNotificationPackage removeJavaEventNotification;
AddAccessibilityEventNotificationPackage addAccessibilityEventNotification;
RemoveAccessibilityEventNotificationPackage removeAccessibilityEventNotification;
// Event contents packages
// PropertyChangePackage propertyChange;
PropertyCaretChangePackage propertyCaretChangePackage;
PropertyDescriptionChangePackage propertyDescriptionChangePackage;
PropertyNameChangePackage propertyNameChangePackage;
PropertySelectionChangePackage propertySelectionChangePackage;
PropertyStateChangePackage propertyStateChangePackage;
PropertyTextChangePackage propertyTextChangePackage;
PropertyValueChangePackage propertyValueChangePackage;
PropertyVisibleDataChangePackage propertyVisibleDataChangePackage;
PropertyChildChangePackage propertyChildChangePackage;
PropertyActiveDescendentChangePackage propertyActiveDescendentChangePackage;
PropertyTableModelChangePackage propertyTableModelChangePackage;
JavaShutdownPackage JavaShutdown;
FocusGainedPackage focusGained;
FocusLostPackage focusLost;
CaretUpdatePackage caretUpdate;
MouseClickedPackage mouseClicked;
MouseEnteredPackage mouseEntered;
MouseExitedPackage mouseExited;
MousePressedPackage mousePressed;
MouseReleasedPackage mouseReleased;
MenuCanceledPackage menuCanceled;
MenuDeselectedPackage menuDeselected;
MenuSelectedPackage menuSelected;
PopupMenuCanceledPackage popupMenuCanceled;
PopupMenuWillBecomeInvisiblePackage popupMenuWillBecomeInvisible;
PopupMenuWillBecomeVisiblePackage popupMenuWillBecomeVisible;
// AccessibleRelationSet
GetAccessibleRelationSetPackage getAccessibleRelationSet;
// AccessibleHypertext
GetAccessibleHypertextPackage _getAccessibleHypertext;
ActivateAccessibleHyperlinkPackage _activateAccessibleHyperlink;
GetAccessibleHyperlinkCountPackage _getAccessibleHyperlinkCount;
GetAccessibleHypertextExtPackage _getAccessibleHypertextExt;
GetAccessibleHypertextLinkIndexPackage _getAccessibleHypertextLinkIndex;
GetAccessibleHyperlinkPackage _getAccessibleHyperlink;
// Accessible KeyBinding, Icon and Action
GetAccessibleKeyBindingsPackage getAccessibleKeyBindings;
GetAccessibleIconsPackage getAccessibleIcons;
GetAccessibleActionsPackage getAccessibleActions;
DoAccessibleActionsPackage doAccessibleActions;
// utility methods
SetTextContentsPackage _setTextContents;
GetParentWithRolePackage _getParentWithRole;
GetTopLevelObjectPackage _getTopLevelObject;
GetParentWithRoleElseRootPackage _getParentWithRoleElseRoot;
GetObjectDepthPackage _getObjectDepth;
GetActiveDescendentPackage _getActiveDescendent;
// Additional methods for Teton
GetVirtualAccessibleNamePackage _getVirtualAccessibleName;
RequestFocusPackage _requestFocus;
SelectTextRangePackage _selectTextRange;
GetTextAttributesInRangePackage _getTextAttributesInRange;
GetVisibleChildrenCountPackage _getVisibleChildrenCount;
GetVisibleChildrenPackage _getVisibleChildren;
SetCaretPositionPackage _setCaretPosition;
} AllPackages;
/**
* Union of all Java-initiated package contents
*/
typedef union JavaInitiatedPackagesTag {
// Initial Rendezvous packages
JavaVMCreatedPackage javaVMCreatedPackage;
JavaVMDestroyedPackage javaVMDestroyedPackage;
JavaVMPresentNotificationPackage javaVMPresentNotificationPackage;
// Event contents packages
PropertyCaretChangePackage propertyCaretChangePackage;
PropertyDescriptionChangePackage propertyDescriptionChangePackage;
PropertyNameChangePackage propertyNameChangePackage;
PropertySelectionChangePackage propertySelectionChangePackage;
PropertyStateChangePackage propertyStateChangePackage;
PropertyTextChangePackage propertyTextChangePackage;
PropertyValueChangePackage propertyValueChangePackage;
PropertyVisibleDataChangePackage propertyVisibleDataChangePackage;
PropertyChildChangePackage propertyChildChangePackage;
PropertyActiveDescendentChangePackage propertyActiveDescendentChangePackage;
PropertyTableModelChangePackage propertyTableModelChangePackage;
JavaShutdownPackage JavaShutdown;
FocusGainedPackage focusGained;
FocusLostPackage focusLost;
CaretUpdatePackage caretUpdate;
MouseClickedPackage mouseClicked;
MouseEnteredPackage mouseEntered;
MouseExitedPackage mouseExited;
MousePressedPackage mousePressed;
MouseReleasedPackage mouseReleased;
MenuCanceledPackage menuCanceled;
MenuDeselectedPackage menuDeselected;
MenuSelectedPackage menuSelected;
PopupMenuCanceledPackage popupMenuCanceled;
PopupMenuWillBecomeInvisiblePackage popupMenuWillBecomeInvisible;
PopupMenuWillBecomeVisiblePackage popupMenuWillBecomeVisible;
} JavaInitiatedPackages;
/**
* Union of all Windows-initiated package contents
*/
typedef union WindowsInitiatedPackagesTag {
// Initial Rendezvous packages
MemoryMappedFileCreatedPackage memoryMappedFileCreatedPackage;
WindowsATCreatedPackage windowsATCreatedPackage;
WindowsATDestroyedPackage windowsATDestroyedPackage;
WindowsATPresentNotificationPackage windowsATPresentNotificationPackage;
// Core packages
ReleaseJavaObjectPackage releaseJavaObject;
GetAccessBridgeVersionPackage getAccessBridgeVersion;
// Window packages
GetAccessibleContextFromHWNDPackage getAccessibleContextFromHWND;
GetHWNDFromAccessibleContextPackage getHWNDFromAccessibleContext;
// AccessibleContext packages
GetAccessibleContextAtPackage getAccessibleContextAt;
GetAccessibleContextWithFocusPackage getAccessibleContextWithFocus;
GetAccessibleContextInfoPackage getAccessibleContextInfo;
GetAccessibleChildFromContextPackage getAccessibleChildFromContext;
GetAccessibleParentFromContextPackage getAccessibleParentFromContext;
// AccessibleText packages
GetAccessibleTextInfoPackage getAccessibleTextInfo;
GetAccessibleTextItemsPackage getAccessibleTextItems;
GetAccessibleTextSelectionInfoPackage getAccessibleTextSelectionInfo;
GetAccessibleTextAttributeInfoPackage getAccessibleTextAttributeInfo;
GetAccessibleTextRectInfoPackage getAccessibleTextRectInfo;
GetAccessibleTextLineBoundsPackage getAccessibleTextLineBounds;
GetAccessibleTextRangePackage getAccessibleTextRange;
// AccessibleValue packages
GetCurrentAccessibleValueFromContextPackage getCurrentAccessibleValueFromContext;
GetMaximumAccessibleValueFromContextPackage getMaximumAccessibleValueFromContext;
GetMinimumAccessibleValueFromContextPackage getMinimumAccessibleValueFromContext;
// AccessibleSelection packages
AddAccessibleSelectionFromContextPackage addAccessibleSelectionFromContext;
ClearAccessibleSelectionFromContextPackage clearAccessibleSelectionFromContext;
GetAccessibleSelectionFromContextPackage getAccessibleSelectionFromContext;
GetAccessibleSelectionCountFromContextPackage getAccessibleSelectionCountFromContext;
IsAccessibleChildSelectedFromContextPackage isAccessibleChildSelectedFromContext;
RemoveAccessibleSelectionFromContextPackage removeAccessibleSelectionFromContext;
SelectAllAccessibleSelectionFromContextPackage selectAllAccessibleSelectionFromContext;
// Event Notification Registration packages
AddJavaEventNotificationPackage addJavaEventNotification;
RemoveJavaEventNotificationPackage removeJavaEventNotification;
AddAccessibilityEventNotificationPackage addAccessibilityEventNotification;
RemoveAccessibilityEventNotificationPackage removeAccessibilityEventNotification;
// AccessibleTable
GetAccessibleTableInfoPackage _getAccessibleTableInfo;
GetAccessibleTableCellInfoPackage _getAccessibleTableCellInfo;
GetAccessibleTableRowHeaderPackage _getAccessibleTableRowHeader;
GetAccessibleTableColumnHeaderPackage _getAccessibleTableColumnHeader;
GetAccessibleTableRowDescriptionPackage _getAccessibleTableRowDescription;
GetAccessibleTableColumnDescriptionPackage _getAccessibleTableColumnDescription;
GetAccessibleTableRowSelectionCountPackage _getAccessibleTableRowSelectionCount;
IsAccessibleTableRowSelectedPackage _isAccessibleTableRowSelected;
GetAccessibleTableRowSelectionsPackage _getAccessibleTableRowSelections;
GetAccessibleTableColumnSelectionCountPackage _getAccessibleTableColumnSelectionCount;
IsAccessibleTableColumnSelectedPackage _isAccessibleTableColumnSelected;
GetAccessibleTableColumnSelectionsPackage _getAccessibleTableColumnSelections;
GetAccessibleTableRowPackage _getAccessibleTableRow;
GetAccessibleTableColumnPackage _getAccessibleTableColumn;
GetAccessibleTableIndexPackage _getAccessibleTableIndex;
// AccessibleRelationSet
GetAccessibleRelationSetPackage _getAccessibleRelationSet;
// Accessible KeyBindings, Icons and Actions
GetAccessibleKeyBindingsPackage _getAccessibleKeyBindings;
GetAccessibleIconsPackage _getAccessibleIcons;
GetAccessibleActionsPackage _getAccessibleActions;
DoAccessibleActionsPackage _doAccessibleActions;
IsSameObjectPackage _isSameObject;
// utility methods
SetTextContentsPackage _setTextContents;
GetParentWithRolePackage _getParentWithRole;
GetTopLevelObjectPackage _getTopLevelObject;
GetParentWithRoleElseRootPackage _getParentWithRoleElseRoot;
GetObjectDepthPackage _getObjectDepth;
GetActiveDescendentPackage _getActiveDescendent;
// Additional methods for Teton
GetVirtualAccessibleNamePackage _getVirtualAccessibleName;
RequestFocusPackage _requestFocus;
SelectTextRangePackage _selectTextRange;
GetTextAttributesInRangePackage _getTextAttributesInRange;
GetVisibleChildrenCountPackage _getVisibleChildrenCount;
GetVisibleChildrenPackage _getVisibleChildren;
SetCaretPositionPackage _setCaretPosition;
} WindowsInitiatedPackages;
#ifdef __cplusplus
}
#endif
#endif
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVASOFT_JAWT_MD_H_
#define _JAVASOFT_JAWT_MD_H_
#include <windows.h>
#include "jawt.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Win32-specific declarations for AWT native interface.
* See notes in jawt.h for an example of use.
*/
typedef struct jawt_Win32DrawingSurfaceInfo {
/* Native window, DDB, or DIB handle */
union {
HWND hwnd;
HBITMAP hbitmap;
void* pbits;
};
/*
* This HDC should always be used instead of the HDC returned from
* BeginPaint() or any calls to GetDC().
*/
HDC hdc;
HPALETTE hpalette;
} JAWT_Win32DrawingSurfaceInfo;
#ifdef __cplusplus
}
#endif
#endif /* !_JAVASOFT_JAWT_MD_H_ */
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#ifndef JNIEXPORT
#define JNIEXPORT __declspec(dllexport)
#endif
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcall
// 'long' is always 32 bit on windows so this matches what jdk expects
typedef long jint;
typedef __int64 jlong;
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */
#include <iostream>
#include <jni.h>
#include <jni_md.h>
#include <jvmti.h>
#include "arthas_VmTool.h" // under target/native/javah/
static jvmtiEnv *jvmti;
static jlong tagCounter = 0;
struct LimitCounter {
jint currentCounter;
jint limitValue;
void init(jint limit) {
currentCounter = 0;
limitValue = limit;
}
void countDown() {
currentCounter++;
}
bool allow() {
if (limitValue < 0) {
return true;
}
return limitValue > currentCounter;
}
};
// 每次 IterateOverInstancesOfClass 调用前需要先 init
static LimitCounter limitCounter = {0, 0};
extern "C"
int init_agent(JavaVM *vm, void *reserved) {
jint rc;
/* Get JVMTI environment */
rc = vm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_2);
if (rc != JNI_OK) {
fprintf(stderr, "ERROR: arthas vmtool Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc);
return -1;
}
jvmtiCapabilities capabilities = {0};
capabilities.can_tag_objects = 1;
jvmtiError error = jvmti->AddCapabilities(&capabilities);
if (error) {
fprintf(stderr, "ERROR: arthas vmtool JVMTI AddCapabilities failed!%u\n", error);
return JNI_FALSE;
}
return JNI_OK;
}
extern "C" JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
return init_agent(vm, reserved);
}
extern "C" JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
return init_agent(vm, reserved);
}
extern "C" JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM* vm, void* reserved) {
init_agent(vm, reserved);
return JNI_VERSION_1_6;
}
extern "C"
JNIEXPORT void JNICALL
Java_arthas_VmTool_forceGc0(JNIEnv *env, jclass thisClass) {
jvmti->ForceGarbageCollection();
}
extern "C"
jlong getTag() {
return ++tagCounter;
}
extern "C"
jvmtiIterationControl JNICALL
HeapObjectCallback(jlong class_tag, jlong size, jlong *tag_ptr, void *user_data) {
jlong *data = static_cast<jlong *>(user_data);
*tag_ptr = *data;
limitCounter.countDown();
if (limitCounter.allow()) {
return JVMTI_ITERATION_CONTINUE;
}else {
return JVMTI_ITERATION_ABORT;
}
}
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_arthas_VmTool_getInstances0(JNIEnv *env, jclass thisClass, jclass klass, jint limit) {
jlong tag = getTag();
limitCounter.init(limit);
jvmtiError error = jvmti->IterateOverInstancesOfClass(klass, JVMTI_HEAP_OBJECT_EITHER,
HeapObjectCallback, &tag);
if (error) {
printf("ERROR: JVMTI IterateOverInstancesOfClass failed!%u\n", error);
return NULL;
}
jint count = 0;
jobject *instances;
error = jvmti->GetObjectsWithTags(1, &tag, &count, &instances, NULL);
if (error) {
printf("ERROR: JVMTI GetObjectsWithTags failed!%u\n", error);
return NULL;
}
jobjectArray array = env->NewObjectArray(count, klass, NULL);
//添加元素到数组
for (int i = 0; i < count; i++) {
env->SetObjectArrayElement(array, i, instances[i]);
}
jvmti->Deallocate(reinterpret_cast<unsigned char *>(instances));
return array;
}
extern "C"
JNIEXPORT jlong JNICALL
Java_arthas_VmTool_sumInstanceSize0(JNIEnv *env, jclass thisClass, jclass klass) {
jlong tag = getTag();
limitCounter.init(-1);
jvmtiError error = jvmti->IterateOverInstancesOfClass(klass, JVMTI_HEAP_OBJECT_EITHER,
HeapObjectCallback, &tag);
if (error) {
printf("ERROR: JVMTI IterateOverInstancesOfClass failed!%u\n", error);
return -1;
}
jint count = 0;
jobject *instances;
error = jvmti->GetObjectsWithTags(1, &tag, &count, &instances, NULL);
if (error) {
printf("ERROR: JVMTI GetObjectsWithTags failed!%u\n", error);
return -1;
}
jlong sum = 0;
for (int i = 0; i < count; i++) {
jlong size = 0;
jvmti->GetObjectSize(instances[i], &size);
sum = sum + size;
}
jvmti->Deallocate(reinterpret_cast<unsigned char *>(instances));
return sum;
}
extern "C"
JNIEXPORT jlong JNICALL Java_arthas_VmTool_getInstanceSize0
(JNIEnv *env, jclass thisClass, jobject instance) {
jlong size = -1;
jvmtiError error = jvmti->GetObjectSize(instance, &size);
if (error) {
printf("ERROR: JVMTI GetObjectSize failed!%u\n", error);
}
return size;
}
extern "C"
JNIEXPORT jlong JNICALL
Java_arthas_VmTool_countInstances0(JNIEnv *env, jclass thisClass, jclass klass) {
jlong tag = getTag();
limitCounter.init(-1);
jvmtiError error = jvmti->IterateOverInstancesOfClass(klass, JVMTI_HEAP_OBJECT_EITHER,
HeapObjectCallback, &tag);
if (error) {
printf("ERROR: JVMTI IterateOverInstancesOfClass failed!%u\n", error);
return -1;
}
jint count = 0;
error = jvmti->GetObjectsWithTags(1, &tag, &count, NULL, NULL);
if (error) {
printf("ERROR: JVMTI GetObjectsWithTags failed!%u\n", error);
return -1;
}
return count;
}
extern "C"
JNIEXPORT jobjectArray JNICALL Java_arthas_VmTool_getAllLoadedClasses0
(JNIEnv *env, jclass thisClass, jclass kclass) {
jclass *classes;
jint count = 0;
jvmtiError error = jvmti->GetLoadedClasses(&count, &classes);
if (error) {
printf("ERROR: JVMTI GetLoadedClasses failed!\n");
return NULL;
}
jobjectArray array = env->NewObjectArray(count, kclass, NULL);
//添加元素到数组
for (int i = 0; i < count; i++) {
env->SetObjectArrayElement(array, i, classes[i]);
}
jvmti->Deallocate(reinterpret_cast<unsigned char *>(classes));
return array;
}
\ No newline at end of file
package arthas;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicLong;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import com.taobao.arthas.common.VmToolUtils;
/**
* 以下本地测试的jvm参数均为:-Xms128m -Xmx128m
*/
public class VmToolTest {
private VmTool initVmTool() {
File path = new File(VmTool.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getParentFile();
String libPath = new File(path, VmToolUtils.detectLibName()).getAbsolutePath();
return VmTool.getInstance(libPath);
}
/**
* macbook上运行结果如下
* allLoadedClasses->1050
* arthas.VmTool@5bb21b69 arthas.VmTool@6b9651f3
* before instances->[arthas.VmTool@5bb21b69, arthas.VmTool@6b9651f3]
* size->16
* count->2
* sum size->32
* null null
* after instances->[]
*/
@Test
public void testIsSnapshot() {
try {
VmTool vmtool = initVmTool();
//调用native方法,获取已加载的类,不包括小类型(如int)
Class<?>[] allLoadedClasses = vmtool.getAllLoadedClasses();
System.out.println("allLoadedClasses->" + allLoadedClasses.length);
//通过下面的例子,可以看到getInstances(Class<T> klass)拿到的是当前存活的所有对象
WeakReference<VmToolTest> weakReference1 = new WeakReference<VmToolTest>(new VmToolTest());
WeakReference<VmToolTest> weakReference2 = new WeakReference<VmToolTest>(new VmToolTest());
System.out.println(weakReference1.get() + " " + weakReference2.get());
VmTool[] beforeInstances = vmtool.getInstances(VmTool.class);
System.out.println("before instances->" + beforeInstances);
System.out.println("size->" + vmtool.getInstanceSize(weakReference1.get()));
System.out.println("count->" + vmtool.countInstances(VmTool.class));
System.out.println("sum size->" + vmtool.sumInstanceSize(VmTool.class));
beforeInstances = null;
vmtool.forceGc();
Thread.sleep(100);
System.out.println(weakReference1.get() + " " + weakReference2.get());
VmTool[] afterInstances = vmtool.getInstances(VmTool.class);
System.out.println("after instances->" + afterInstances);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testGetInstancesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool vmtool = initVmTool();
final AtomicLong totalTime = new AtomicLong();
//本地测试请改成200000
for (int i = 1; i <= 2; i++) {
long start = System.currentTimeMillis();
WeakReference<Object[]> reference = new WeakReference<Object[]>(vmtool.getInstances(Object.class));
Object[] instances = reference.get();
long cost = System.currentTimeMillis() - start;
totalTime.addAndGet(cost);
System.out.println(i + " instance size:" + (instances == null ? 0 : instances.length) + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
instances = null;
vmtool.forceGc();
}
}
@Test
public void testSumInstancesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool vmtool = initVmTool();
final AtomicLong totalTime = new AtomicLong();
//本地测试请改成200000
for (int i = 1; i <= 2; i++) {
long start = System.currentTimeMillis();
long sum = vmtool.sumInstanceSize(Object.class);
long cost = System.currentTimeMillis() - start;
totalTime.addAndGet(cost);
System.out.println(i + " sum:" + sum + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
}
}
@Test
public void testCountInstancesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool vmtool = initVmTool();
final AtomicLong totalTime = new AtomicLong();
//本地测试请改成200000
for (int i = 1; i <= 2; i++) {
long start = System.currentTimeMillis();
long count = vmtool.countInstances(Object.class);
long cost = System.currentTimeMillis() - start;
totalTime.addAndGet(cost);
System.out.println(i + " count:" + count + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
}
}
@Test
public void testGetAllLoadedClassesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool vmtool = initVmTool();
final AtomicLong totalTime = new AtomicLong();
//本地测试请改成200000
for (int i = 1; i <= 2; i++) {
long start = System.currentTimeMillis();
Class<?>[] allLoadedClasses = vmtool.getAllLoadedClasses();
long cost = System.currentTimeMillis() - start;
totalTime.addAndGet(cost);
System.out.println(i + " class size:" + allLoadedClasses.length + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
allLoadedClasses = null;
}
}
class LimitTest {
}
@Test
public void test_getInstances_lmiit() {
VmTool vmtool = initVmTool();
ArrayList<LimitTest> list = new ArrayList<LimitTest>();
for (int i = 0; i < 10; ++i) {
list.add(new LimitTest());
}
LimitTest[] instances = vmtool.getInstances(LimitTest.class, 5);
Assertions.assertThat(instances).hasSize(5);
LimitTest[] instances2 = vmtool.getInstances(LimitTest.class, -1);
Assertions.assertThat(instances2).hasSize(10);
LimitTest[] instances3 = vmtool.getInstances(LimitTest.class, 1);
Assertions.assertThat(instances3).hasSize(1);
}
interface III {
}
class AAA implements III {
}
@Test
public void test_getInstances_interface() {
AAA aaa = new AAA();
VmTool vmtool = initVmTool();
III[] interfaceInstances = vmtool.getInstances(III.class);
Assertions.assertThat(interfaceInstances.length).isEqualTo(1);
AAA[] ObjectInstances = vmtool.getInstances(AAA.class);
Assertions.assertThat(ObjectInstances.length).isEqualTo(1);
Assertions.assertThat(interfaceInstances[0]).isEqualTo(ObjectInstances[0]);
}
}
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
get_local_maven_project_version()
{
"$DIR/mvnw" -T 2C -Dmaven.test.skip=true -DskipTests=true -Dmaven.javadoc.skip=true org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate \
-Dexpression=project.version -f $DIR/pom.xml -B | grep -e '^[^\[]' | cut -b 1-5
}
"$DIR/mvnw" -version
CUR_VERSION=$(get_local_maven_project_version)
# arthas's version
DATE=$(date '+%Y%m%d%H%M%S')
ARTHAS_VERSION="${CUR_VERSION}.${DATE}"
echo "${ARTHAS_VERSION}" > $DIR/core/src/main/resources/com/taobao/arthas/core/res/version
# define newset arthas lib home
NEWEST_ARTHAS_LIB_HOME=${HOME}/.arthas/lib/${ARTHAS_VERSION}/arthas
# exit shell with err_code
# $1 : err_code
# $2 : err_msg
exit_on_err()
{
[[ ! -z "${2}" ]] && echo "${2}" 1>&2
exit ${1}
}
# maven package the arthas
"$DIR/mvnw" clean package -Dmaven.test.skip=true -DskipTests=true -Dmaven.javadoc.skip=true -f $DIR/pom.xml \
|| exit_on_err 1 "package arthas failed."
rm -r "$DIR/core/src/main/resources/com/taobao/arthas/core/res/version"
packaging_bin_path=$(ls "${DIR}"/packaging/target/arthas-bin.zip)
# install to local
mkdir -p "${NEWEST_ARTHAS_LIB_HOME}"
unzip ${packaging_bin_path} -d "${NEWEST_ARTHAS_LIB_HOME}/"
# print ~/.arthas directory size
arthas_dir_size="$(du -hs ${HOME}/.arthas | cut -f1)"
echo "${HOME}/.arthas size: ${arthas_dir_size}"
\ No newline at end of file
dashboard -n 1
sysprop
watch arthas.Test test "@com.alibaba.arthas.Test@n.entrySet().iterator.{? #this.key.name()=='STOP' }" -n 2
@echo off
REM DON'T CHANGE THE FIRST LINE OF THE FILE, WINDOWS SERVICE RUN BAT NEED IT! (@echo off)
REM don't call 'echo' before 'start as.bat'
REM You can specify Java Home via AS_JAVA_HOME here or Windows System Environment, but not in cmd.exe
REM set AS_JAVA_HOME=C:\Program Files\Java\jdk1.8.0_131
set basedir=%~dp0
set filename=%~nx0
set srv_name=arthas
set telnet_port=3658
set http_port=8563
REM parse extend args
set arg1=%1
set pid=
set port=
set ignoreTools=0
set as_remove_srv=0
set as_service=0
set srv_interact=0
for %%a in (%*) do (
if "%%a"=="--remove" set as_remove_srv=1
if "%%a"=="--service" set as_service=1
if "%%a"=="--interact" set srv_interact=1
if "%%a"=="--ignore-tools" set ignoreTools=1
)
REM Parse command line args (https://stackoverflow.com/a/35445653)
:read_params
if not %1/==/ (
if not "%__var%"=="" (
if not "%__var:~0,1%"=="-" (
endlocal
goto read_params
)
endlocal & set %__var:~1%=%~1
) else (
setlocal & set __var=%~1
)
shift
goto read_params
)
if not "%telnet-port%"=="" set telnet_port=%telnet-port%
if not "%http-port%"=="" set http_port=%http-port%
REM Setup JAVA_HOME
REM Decode -java-home: '@' -> ' '
if not "%java-home%"=="" set JAVA_HOME=%java-home:@= %
REM If has AS_JAVA_HOME, overriding JAVA_HOME
if not "%AS_JAVA_HOME%" == "" set JAVA_HOME=%AS_JAVA_HOME%
REM use defined is better then "%var%" == "", avoid trouble of ""
if not defined JAVA_HOME goto noJavaHome
REM Remove "" in path
set JAVA_HOME=%JAVA_HOME:"=%
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
if %ignoreTools% == 1 (
echo Ignore tools.jar, make sure the java version ^>^= 9
) else (
if not exist "%JAVA_HOME%\lib\tools.jar" (
echo Can not find lib\tools.jar under %JAVA_HOME%!
echo If java version ^<^= 1.8, please make sure JAVA_HOME point to a JDK not a JRE.
echo If java version ^>^= 9, try to run %filename% ^<pid^> --ignore-tools
goto :end
)
)
set JAVACMD="%JAVA_HOME%\bin\java"
REM Runas Service, don't call 'echo' before 'start as.bat'
set as_args=-telnet-port %telnet_port% -http-port %http_port%
if %srv_interact%==0 set as_args=%as_args% --no-interact
if %ignoreTools%==1 set as_args=%as_args% --ignore-tools
if %as_service%==1 (
REM run as.bat
start /wait %basedir%\as.bat %pid% %as_args%
exit 0
REM DEBUG run args
REM echo as_args: %as_args%
REM echo start /wait %basedir%\as.bat %pid% %as_args%
REM exit /b 0
)
REM If the first arg is a number, then set it as pid
echo %arg1%| findstr /r "^[1-9][0-9]*$">nul
if %errorlevel% equ 0 set pid=%arg1%
echo pid: %pid%
echo port: %port%
if not ["%pid%"] == [""] (
goto :prepare_srv
)
if not ["%port%"] == [""] (
goto :find_port
)
if %as_remove_srv%==1 (
goto :remove_srv
)
goto :usage
:remove_srv
echo Removing service: %srv_name% ...
sc stop %srv_name%
sc delete %srv_name%
exit /b 0
:find_port
netstat -nao |findstr LIST |findstr :%telnet_port%
IF %ERRORLEVEL% EQU 0 (
echo Arthas agent already running, just connect to it!
goto :attachSuccess
)
@rem find pid by port
echo %port%| findstr /r "^[1-9][0-9]*$">nul
if %errorlevel% neq 0 (
echo port is not valid number!
goto :usage
)
echo Finding process of listening on port: %port%
set query_pid_command='netstat -ano ^^^| findstr ":%port%" ^^^| findstr "LISTENING"'
set pid=
for /f "tokens=5" %%i in (%query_pid_command%) do (
set pid=%%i
)
if "%pid%" == "" (
echo None process listening on port: %port%
goto :end
)
echo Target process pid is %pid%
:prepare_srv
REM check telnet port
netstat -nao |findstr LIST |findstr :%telnet_port%
IF %ERRORLEVEL% EQU 0 (
echo Arthas agent already running, just connect to it!
goto :attachSuccess
)
REM validate pid
echo %pid%| findstr /r "^[1-9][0-9]*$">nul
if %errorlevel% neq 0 (
echo PID is not valid number!
goto :usage
)
echo Preparing arthas service and injecting arthas agent to process: %pid% ...
REM encode java path, avoid space in service args: ' ' -> '@'
set srv_java_home=-java-home %JAVA_HOME: =@%
set srv_args=-pid %pid% -telnet-port %telnet_port% -http-port %http_port% %srv_java_home%
if %srv_interact%==1 (
sc start UI0Detect
set srv_type=type= interact type= own
set srv_binpath=binPath= "%basedir%\%filename% %srv_args% --service --interact"
) else (
set srv_type=type= own
set srv_binpath=binPath= "%basedir%\%filename% %srv_args% --service"
)
echo arthas srv type: %srv_type%
echo arthas srv binPath: %srv_binpath%
sc create %srv_name% start= demand %srv_type% %srv_binpath%
sc config %srv_name% start= demand %srv_type% %srv_binpath%
if %errorlevel% NEQ 0 (
echo Config Arthas service failed
exit /b -1
)
sc stop %srv_name%
REM fork start Arthas service, avoid blocking
if %srv_interact%==1 (
start /B sc start %srv_name%
)else (
start /B sc start %srv_name% > nul 2>&1
)
REM check and connect arthas ..
echo Waitting for arthas agent ...
set count=0
:waitfor_loop
echo checking
netstat -nao |findstr LIST |findstr :%telnet_port%
IF %ERRORLEVEL% NEQ 0 (
set /a count+=1
if %count% geq 8 (
echo Arthas agent telnet port is not ready, maybe inject failed.
goto :end
)
ping -w 1 -n 2 0.0.0.0 > nul
goto :waitfor_loop
)
echo Arthas agent telnet port is ready.
:attachSuccess
WHERE telnet
IF %ERRORLEVEL% NEQ 0 (
ECHO telnet wasn't found, please google how to install telnet under windows.
ECHO Try to visit http://127.0.0.1:%http_port% to connecto arthas server.
start http://127.0.0.1:%http_port%
) else (
telnet 127.0.0.1 %telnet_port%
)
echo(
echo Checking arthas telnet port [:%telnet_port%] ...
netstat -nao |findstr LIST |findstr :%telnet_port%
IF %ERRORLEVEL% EQU 0 (
echo Arthas agent is still running!
goto :choice
) else (
echo Arthas agent is shutdown.
goto :end
)
:choice
set /P c=Are you going to shutdown arthas agent [Y/N]?
echo input: %c%
if /I "%c%" EQU "Y" goto :shutdown_agent
if /I "%c%" EQU "N" goto :end
goto :choice
:shutdown_agent
echo Shutting down arthas ...
%JAVACMD% -jar arthas-client.jar -c shutdown 127.0.0.1 %telnet_port%
@rem check telnet port agian
echo Checking arthas telnet port [:%telnet_port%] ...
netstat -nao |findstr LIST |findstr :%telnet_port%
IF %ERRORLEVEL% EQU 0 (
echo Arthas shutdown failed!
) else (
echo Arthas shutdown successfully.
)
goto :end
:usage
echo Arthas for Windows Service.
echo Usage:
echo %filename% java_pid [option] ..
echo %filename% [-pid java_pid] [option] ..
echo %filename% [-port java_port] [option] ..
echo(
echo Options:
echo -pid java_pid : Attach by java process pid
echo -port java_port : Attach by java process listen port
echo -telnet-port port : Change arthas telnet port
echo -http-port port : Change arthas http/websocket port
echo --interact : Enable windows service interactive UI, useful for debug
echo --remove : Remove Arthas windows service
echo --ignore-tools : Ignore checking JAVA_HOME\lib\tools.jar for jdk 9/10/11
echo(
echo Example:
echo %filename% 2351
echo %filename% 2351 -telnet-port 2000 -http-port 2001
echo %filename% -pid 2351
echo %filename% -port 8080 --interact
echo %filename% --remove #remove arthas service
exit /b -1
:noJavaHome
echo JAVA_HOME: %JAVA_HOME%
echo The JAVA_HOME environment variable is not defined correctly.
echo It is needed to run this program.
echo NB: JAVA_HOME should point to a JDK not a JRE.
exit /b -1
:end
@echo off
REM ----------------------------------------------------------------------------
REM program : Arthas
REM author : Core Engine @ Taobao.com
REM date : 2015-11-11
REM version : 3.0
REM ----------------------------------------------------------------------------
set ERROR_CODE=0
set TELNET_PORT=3658
set HTTP_PORT=8563
set BASEDIR=%~dp0
if ["%~1"]==[""] (
echo Example:
echo %~nx0 452
echo %~nx0 452 --ignore-tools # for jdk 9/10/11
echo(
echo Need the pid argument, you can run jps to list all java process ids.
goto exit_bat
)
set JAVA_TOOL_OPTIONS
set AGENT_JAR=%BASEDIR%\arthas-agent.jar
set CORE_JAR=%BASEDIR%\arthas-core.jar
set PID=%1
echo %PID%| findstr /r "^[1-9][0-9]*$">nul
if %errorlevel% neq 0 (
echo PID is not valid number!
echo Example:
echo %~nx0 452
echo %~nx0 452 --ignore-tools # for jdk 9/10/11
echo(
echo Need the pid argument, you can run jps to list all java process ids.
goto exit_bat
)
REM parse extend args
set ignoreTools=0
set exitProcess=0
for %%a in (%*) do (
if "%%a"=="--no-interact" set exitProcess=1
if "%%a"=="--ignore-tools" set ignoreTools=1
)
REM from https://stackoverflow.com/a/35445653
:read_params
if not %1/==/ (
if not "%__var%"=="" (
if not "%__var:~0,1%"=="-" (
endlocal
goto read_params
)
endlocal & set %__var:~1%=%~1
) else (
setlocal & set __var=%~1
)
shift
goto read_params
)
if not "%telnet-port%"=="" set TELNET_PORT=%telnet-port%
if not "%http-port%"=="" set HTTP_PORT=%http-port%
echo JAVA_HOME: %JAVA_HOME%
echo telnet port: %TELNET_PORT%
echo http port: %HTTP_PORT%
REM Setup JAVA_HOME
if "%JAVA_HOME%" == "" goto noJavaHome
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
if %ignoreTools% == 1 (
echo Ignore tools.jar, make sure the java version ^>^= 9
) else (
if not exist "%JAVA_HOME%\lib\tools.jar" (
echo Can not find lib\tools.jar under %JAVA_HOME%!
echo If java version ^<^= 1.8, please make sure JAVA_HOME point to a JDK not a JRE.
echo If java version ^>^= 9, try to run as.bat ^<pid^> --ignore-tools
goto exit_bat
)
set BOOT_CLASSPATH="-Xbootclasspath/a:%JAVA_HOME%\lib\tools.jar"
)
set JAVACMD="%JAVA_HOME%\bin\java"
goto okJava
:noJavaHome
echo The JAVA_HOME environment variable is not defined correctly.
echo It is needed to run this program.
echo NB: JAVA_HOME should point to a JDK not a JRE.
goto exit_bat
:okJava
%JAVACMD% -Dfile.encoding=UTF-8 %BOOT_CLASSPATH% -jar "%CORE_JAR%" -pid "%PID%" -target-ip 127.0.0.1 -telnet-port %TELNET_PORT% -http-port %HTTP_PORT% -core "%CORE_JAR%" -agent "%AGENT_JAR%"
if %ERRORLEVEL% NEQ 0 goto exit_bat
if %exitProcess%==1 goto exit_bat
goto attachSuccess
:attachSuccess
WHERE telnet
IF %ERRORLEVEL% NEQ 0 (
ECHO telnet wasn't found, please google how to install telnet under windows.
ECHO Try to visit http://127.0.0.1:%HTTP_PORT% to connecto arthas server.
start http://127.0.0.1:%HTTP_PORT%
) else (
telnet 127.0.0.1 %TELNET_PORT%
)
:exit_bat
if %exitProcess%==1 exit %ERROR_CODE%
exit /B %ERROR_CODE%
#!/usr/bin/env bash
# WIKI: https://arthas.aliyun.com/doc
# This script only supports bash, do not support posix sh.
# If you have the problem like Syntax error: "(" unexpected (expecting "fi"),
# Try to run "bash -version" to check the version.
# Try to visit WIKI to find a solution.
# program : Arthas
# author : Core Engine @ Taobao.com
# date : 2022-07-30
# current arthas script version
ARTHAS_SCRIPT_VERSION=3.6.4
# SYNOPSIS
# rreadlink <fileOrDirPath>
# DESCRIPTION
# Resolves <fileOrDirPath> to its ultimate target, if it is a symlink, and
# prints its canonical path. If it is not a symlink, its own canonical path
# is printed.
# A broken symlink causes an error that reports the non-existent target.
# LIMITATIONS
# - Won't work with filenames with embedded newlines or filenames containing
# the string ' -> '.
# COMPATIBILITY
# This is a fully POSIX-compliant implementation of what GNU readlink's
# -e option does.
# EXAMPLE
# In a shell script, use the following to get that script's true directory of origin:
# trueScriptDir=$(dirname -- "$(rreadlink "$0")")
rreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.
target=$1 fname= targetDir= CDPATH=
# Try to make the execution environment as predictable as possible:
# All commands below are invoked via `command`, so we must make sure that
# `command` itself is not redefined as an alias or shell function.
# (Note that command is too inconsistent across shells, so we don't use it.)
# `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not
# even have an external utility version of it (e.g, Ubuntu).
# `command` bypasses aliases and shell functions and also finds builtins
# in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for
# that to happen.
{ \unalias command; \unset -f command; } >/dev/null 2>&1
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.
while :; do # Resolve potential symlinks until the ultimate target is found.
[ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; }
command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
fname=$(command basename -- "$target") # Extract filename.
[ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/'
if [ -L "$fname" ]; then
# Extract [next] target path, which may be defined
# *relative* to the symlink's own directory.
# Note: We parse `ls -l` output to find the symlink target
# which is the only POSIX-compliant, albeit somewhat fragile, way.
target=$(command ls -l "$fname")
target=${target#* -> }
continue # Resolve [next] symlink target.
fi
break # Ultimate target reached.
done
targetDir=$(command pwd -P) # Get canonical dir. path
# Output the ultimate target's canonical path.
# Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.
if [ "$fname" = '.' ]; then
command printf '%s\n' "${targetDir%/}"
elif [ "$fname" = '..' ]; then
# Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied
# AFTER canonicalization.
command printf '%s\n' "$(command dirname -- "${targetDir}")"
else
command printf '%s\n' "${targetDir%/}/$fname"
fi
)
DIR=$(dirname -- "$(rreadlink "${BASH_SOURCE[0]}")")
############ Command Arguments ############
# define arthas's home
ARTHAS_HOME=
# define arthas's lib
if [ -z "${ARTHAS_LIB_DIR}" ]; then
ARTHAS_LIB_DIR=${HOME}/.arthas/lib
fi
# target process id to attach
TARGET_PID=
# target process id to attach, default 127.0.0.1
TARGET_IP=
DEFAULT_TARGET_IP="127.0.0.1"
# telnet port, default 3658
TELNET_PORT=
DEFAULT_TELNET_PORT="3658"
# http port, default 8563
HTTP_PORT=
DEFAULT_HTTP_PORT="8563"
# telnet session timeout seconds, default 1800
SESSION_TIMEOUT=
# use specify version
USE_VERSION=
# remote repo to download arthas
REPO_MIRROR=
# use http to download arthas
USE_HTTP=false
# attach only, do not telnet connect
ATTACH_ONLY=false
# pass debug arguments to the attach java process
DEBUG_ATTACH=false
# arthas-client terminal height
HEIGHT=
# arthas-client terminal width
WIDTH=
# select target process by classname or JARfilename
SELECT=
# Verbose, print debug info.
VERBOSE=false
# command to execute
COMMAND=
# batch file to execute
BATCH_FILE=
# tunnel server url
TUNNEL_SERVER=
# agent id
AGENT_ID=
# stat report url
STAT_URL=
# app name
APP_NAME=
# username
USERNAME=
# password
PASSWORD=
# disabledCommands
DISABLED_COMMANDS=
############ Command Arguments ############
# if arguments contains -c/--command or -f/--batch-file, BATCH_MODE will be true
BATCH_MODE=false
# define arthas's temp dir
TMP_DIR=/tmp
# arthas remote url
# https://arthas.aliyun.com/download/3.1.7?mirror=aliyun
REMOTE_DOWNLOAD_URL="https://arthas.aliyun.com/download/PLACEHOLDER_VERSION?mirror=PLACEHOLDER_REPO"
# update timeout(sec)
SO_TIMEOUT=5
# define JVM's OPS
JVM_OPTS=""
ARTHAS_OPTS="-Djava.awt.headless=true"
OS_TYPE=
case "$(uname -s)" in
Linux*) OS_TYPE=Linux;;
Darwin*) OS_TYPE=Mac;;
CYGWIN*) OS_TYPE=Cygwin;;
MINGW*) OS_TYPE=MinGw;;
*) OS_TYPE="UNKNOWN"
esac
# check curl/grep/awk/telnet/unzip command
if ! [ -x "$(command -v curl)" ]; then
echo 'Error: curl is not installed. Try to use java -jar arthas-boot.jar' >&2
exit 1
fi
if ! [ -x "$(command -v grep)" ]; then
echo 'Error: grep is not installed. Try to use java -jar arthas-boot.jar' >&2
exit 1
fi
if ! [ -x "$(command -v awk)" ]; then
echo 'Error: awk is not installed. Try to use java -jar arthas-boot.jar' >&2
exit 1
fi
if ! [ -x "$(command -v telnet)" ]; then
echo 'Error: telnet is not installed. Try to use java -jar arthas-boot.jar' >&2
exit 1
fi
if ! [ -x "$(command -v unzip)" ]; then
echo 'Error: unzip is not installed. Try to use java -jar arthas-boot.jar' >&2
exit 1
fi
# exit shell with err_code
# $1 : err_code
# $2 : err_msg
exit_on_err()
{
[[ ! -z "${2}" ]] && echo "${2}" 1>&2
exit ${1}
}
# get with default value
# $1 : target value
# $2 : default value
default()
{
[[ ! -z "${1}" ]] && echo "${1}" || echo "${2}"
}
# check arthas permission
check_permission()
{
[ ! -w "${HOME}" ] \
&& exit_on_err 1 "permission denied, ${HOME} is not writable."
}
# reset arthas work environment
# reset some options for env
reset_for_env()
{
unset JAVA_TOOL_OPTIONS
# init ARTHAS' lib
mkdir -p "${ARTHAS_LIB_DIR}" \
|| exit_on_err 1 "create ${ARTHAS_LIB_DIR} fail."
# if env define the JAVA_HOME, use it first
# if is alibaba opts, use alibaba ops's default JAVA_HOME
[ -z "${JAVA_HOME}" ] && [ -d /opt/taobao/java ] && JAVA_HOME=/opt/taobao/java
if [[ (-z "${JAVA_HOME}") && ( -e "/usr/libexec/java_home") ]]; then
# for mac
JAVA_HOME=`/usr/libexec/java_home`
fi
if [ -z "${JAVA_HOME}" ]; then
# try to find JAVA_HOME from java command
local JAVA_COMMAND_PATH=$( rreadlink $(type -p java) )
JAVA_HOME=$(echo "$JAVA_COMMAND_PATH" | sed -n 's/\/bin\/java$//p')
fi
# iterater throught candidates to find a proper JAVA_HOME at least contains tools.jar which is required by arthas.
if [ ! -d "${JAVA_HOME}" ]; then
JAVA_HOME_CANDIDATES=($(ps aux | grep java | grep -v 'grep java' | awk '{print $11}' | sed -n 's/\/bin\/java$//p'))
for JAVA_HOME_TEMP in ${JAVA_HOME_CANDIDATES[@]}; do
if [ -f "${JAVA_HOME_TEMP}/lib/tools.jar" ]; then
JAVA_HOME=`rreadlink "${JAVA_HOME_TEMP}"`
break
fi
done
fi
if [ -z "${JAVA_HOME}" ]; then
exit_on_err 1 "Can not find JAVA_HOME, please set \$JAVA_HOME bash env first."
fi
# maybe 1.8.0_162 , 11-ea
local JAVA_VERSION
local IFS=$'\n'
# remove \r for Cygwin
local lines=$("${JAVA_HOME}"/bin/java -version 2>&1 | tr '\r' '\n')
for line in $lines; do
if [[ (-z $JAVA_VERSION) && ($line = *"version \""*) ]]
then
local ver=$(echo $line | sed -e 's/.*version "\(.*\)"\(.*\)/\1/; 1q')
# on macOS, sed doesn't support '?'
if [[ $ver = "1."* ]]
then
JAVA_VERSION=$(echo $ver | sed -e 's/1\.\([0-9]*\)\(.*\)/\1/; 1q')
else
JAVA_VERSION=$(echo $ver | sed -e 's/\([0-9]*\)\(.*\)/\1/; 1q')
fi
fi
done
# when java version less than 9, we can use tools.jar to confirm java home.
# when java version greater than 9, there is no tools.jar.
if [[ "$JAVA_VERSION" -lt 9 ]];then
# possible java homes
javaHomes=("${JAVA_HOME%%/}" "${JAVA_HOME%%/}/.." "${JAVA_HOME%%/}/../..")
for javaHome in ${javaHomes[@]}
do
toolsJar="$javaHome/lib/tools.jar"
if [ -f $toolsJar ]; then
JAVA_HOME=$( rreadlink $javaHome )
BOOT_CLASSPATH=-Xbootclasspath/a:$( rreadlink $toolsJar )
break
fi
done
[ -z "${BOOT_CLASSPATH}" ] && exit_on_err 1 "tools.jar was not found, so arthas could not be launched!"
fi
echo "[INFO] JAVA_HOME: ${JAVA_HOME}"
# reset CHARSET for alibaba opts, we use GBK
[[ -x /opt/taobao/java ]] && JVM_OPTS="-Dinput.encoding=GBK ${JVM_OPTS} "
}
# get latest version from local
get_local_version()
{
ls "${ARTHAS_LIB_DIR}" | sort | tail -1
}
get_repo_url()
{
local repoUrl="${REPO_MIRROR}"
if [ "$USE_HTTP" = true ] ; then
repoUrl=${repoUrl/https/http}
fi
echo "${repoUrl}"
}
# get latest version from remote
get_remote_version()
{
curl -sLk "https://arthas.aliyun.com/api/latest_version"
}
# check version greater
version_gt()
{
local remote_version=$1
local arthas_local_version=$2
[[ "$remote_version" > "$arthas_local_version" ]] && return 0 || return 1
}
# update arthas if necessary
update_if_necessary()
{
local update_version=$1
if [ ! -d "${ARTHAS_LIB_DIR}/${update_version}" ]; then
echo "updating version ${update_version} ..."
local temp_target_lib_dir="$TMP_DIR/temp_${update_version}_$$"
local temp_target_lib_zip="${temp_target_lib_dir}/arthas-${update_version}-bin.zip"
local target_lib_dir="${ARTHAS_LIB_DIR}/${update_version}/arthas"
# clean
rm -rf "${temp_target_lib_dir}"
rm -rf "${target_lib_dir}"
mkdir -p "${temp_target_lib_dir}" \
|| exit_on_err 1 "create ${temp_target_lib_dir} fail."
# download current arthas version
local downloadUrl="${REMOTE_DOWNLOAD_URL//PLACEHOLDER_REPO/$(get_repo_url)}"
downloadUrl="${downloadUrl//PLACEHOLDER_VERSION/${update_version}}"
echo "Download arthas from: ${downloadUrl}"
curl \
-#Lk \
--connect-timeout ${SO_TIMEOUT} \
-o "${temp_target_lib_zip}" \
"${downloadUrl}" \
|| return 1
# unzip arthas lib
if ! (unzip "${temp_target_lib_zip}" -d "${temp_target_lib_dir}") ; then
rm -rf "${temp_target_lib_dir}" "${ARTHAS_LIB_DIR}/${update_version}"
return 1
fi
mkdir -p "${ARTHAS_LIB_DIR}/${update_version}"
# rename
mv "${temp_target_lib_dir}" "${target_lib_dir}" || return 1
# print success
echo "update completed."
fi
}
call_jps()
{
if [ "${VERBOSE}" = true ] ; then
"${JAVA_HOME}"/bin/jps -l -v
else
"${JAVA_HOME}"/bin/jps -l
fi
}
# the usage
usage()
{
echo "
Usage:
$0 [-h] [--target-ip <value>] [--telnet-port <value>]
[--http-port <value>] [--session-timeout <value>] [--arthas-home <value>]
[--tunnel-server <value>] [--agent-id <value>] [--stat-url <value>]
[--app-name <value>]
[--username <value>] [--password <value>]
[--disabled-commands <value>]
[--use-version <value>] [--repo-mirror <value>] [--versions] [--use-http]
[--attach-only] [-c <value>] [-f <value>] [-v] [pid]
Options and Arguments:
-h,--help Print usage
--target-ip <value> The target jvm listen ip, default 127.0.0.1
--telnet-port <value> The target jvm listen telnet port, default 3658
--http-port <value> The target jvm listen http port, default 8563
--session-timeout <value> The session timeout seconds, default 1800 (30min)
--arthas-home <value> The arthas home
--use-version <value> Use special version arthas
--repo-mirror <value> Use special remote repository mirror, value is
center/aliyun or http repo url.
--versions List local and remote arthas versions
--use-http Enforce use http to download, default use https
--attach-only Attach target process only, do not connect
--debug-attach Debug attach agent
--tunnel-server Remote tunnel server url
--agent-id Special agent id
--app-name Special app name
--username Special username
--password Special password
--disabled-commands Disable special commands
--select select target process by classname or JARfilename
-c,--command <value> Command to execute, multiple commands separated
by ;
-f,--batch-file <value> The batch file to execute
--height <value> arthas-client terminal height
--width <value> arthas-client terminal width
-v,--verbose Verbose, print debug info.
<pid> Target pid
EXAMPLES:
./as.sh <pid>
./as.sh --target-ip 0.0.0.0
./as.sh --telnet-port 9999 --http-port -1
./as.sh --username admin --password <password>
./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' --app-name demoapp
./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw
./as.sh --stat-url 'http://192.168.10.11:8080/api/stat'
./as.sh -c 'sysprop; thread' <pid>
./as.sh -f batch.as <pid>
./as.sh --use-version 3.6.4
./as.sh --session-timeout 3600
./as.sh --attach-only
./as.sh --disabled-commands stop,dump
./as.sh --select math-game
./as.sh --repo-mirror aliyun --use-http
WIKI:
https://arthas.aliyun.com/doc
Here is the list of possible java process(es) to attatch:
"
call_jps | grep -v sun.tools.jps.Jps
}
# list arthas versions
list_versions()
{
echo "Arthas versions under ${ARTHAS_LIB_DIR}:"
ls -1 "${ARTHAS_LIB_DIR}"
}
# find the process tcp listen at the port
# $1 : port number
find_listen_port_process()
{
if [ -x "$(command -v lsof)" ]; then
echo $(lsof -t -s TCP:LISTEN -i TCP:$1)
fi
}
getTargetIPOrDefault()
{
local targetIP=${DEFAULT_TARGET_IP}
if [ "${TARGET_IP}" ]; then
targetIP=${TARGET_IP}
fi
echo $targetIP
}
getTelnetPortOrDefault()
{
local telnetPort=${DEFAULT_TELNET_PORT}
if [ "${TELNET_PORT}" ]; then
telnetPort=${TELNET_PORT}
fi
echo $telnetPort
}
getHttpPortOrDefault()
{
local httpPort=${DEFAULT_HTTP_PORT}
if [ "${HTTP_PORT}" ]; then
httpPort=${HTTP_PORT}
fi
echo $httpPort
}
# Status from com.taobao.arthas.client.TelnetConsole
# Execute commands timeout
STATUS_EXEC_TIMEOUT=100
# Execute commands error
STATUS_EXEC_ERROR=101
# find the process pid of target telnet port
# maybe another user start an arthas server at the same port, but invisible for current user
find_listen_port_process_by_client()
{
local arthas_lib_dir="${ARTHAS_HOME}"
# http://www.inonit.com/cygwin/faq/
if [ "${OS_TYPE}" = "Cygwin" ]; then
arthas_lib_dir=`cygpath -wp "$arthas_lib_dir"`
fi
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \
$(getTargetIPOrDefault) \
$(getTelnetPortOrDefault) \
-c "session" \
--execution-timeout 2000 \
2>&1
# return java process exit status code !
return $?
}
parse_arguments()
{
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-h|--help)
usage
exit 0
;;
--versions)
list_versions
exit 0
;;
--target-ip)
TARGET_IP="$2"
shift # past argument
shift # past value
;;
--telnet-port)
TELNET_PORT="$2"
shift # past argument
shift # past value
;;
--http-port)
HTTP_PORT="$2"
shift # past argument
shift # past value
;;
--session-timeout)
SESSION_TIMEOUT="$2"
shift # past argument
shift # past value
;;
--arthas-home)
ARTHAS_HOME="$2"
shift # past argument
shift # past value
;;
--use-version)
USE_VERSION="$2"
shift # past argument
shift # past value
;;
--repo-mirror)
REPO_MIRROR="$2"
shift # past argument
shift # past value
;;
-c|--command)
COMMAND="$2"
BATCH_MODE=true
shift # past argument
shift # past value
;;
-f|--batch-file)
BATCH_FILE="$2"
BATCH_MODE=true
shift # past argument
shift # past value
;;
--tunnel-server)
TUNNEL_SERVER="$2"
shift # past argument
shift # past value
;;
--agent-id)
AGENT_ID="$2"
shift # past argument
shift # past value
;;
--stat-url)
STAT_URL="$2"
shift # past argument
shift # past value
;;
--app-name)
APP_NAME="$2"
shift # past argument
shift # past value
;;
--username)
USERNAME="$2"
shift # past argument
shift # past value
;;
--password)
PASSWORD="$2"
shift # past argument
shift # past value
;;
--disabled-commands)
DISABLED_COMMANDS="$2"
shift # past argument
shift # past value
;;
--use-http)
USE_HTTP=true
shift # past argument
;;
--attach-only)
ATTACH_ONLY=true
shift # past argument
;;
--debug-attach)
DEBUG_ATTACH=true
if [ -z "$JPDA_TRANSPORT" ]; then
JPDA_TRANSPORT="dt_socket"
fi
if [ -z "$JPDA_ADDRESS" ]; then
JPDA_ADDRESS="8888"
fi
if [ -z "$JPDA_SUSPEND" ]; then
JPDA_SUSPEND="y"
fi
if [ -z "$JPDA_OPTS" ]; then
JPDA_OPTS="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND"
fi
ARTHAS_OPTS="$JPDA_OPTS $ARTHAS_OPTS"
shift # past argument
;;
--height)
HEIGHT="$2"
shift # past argument
shift # past value
;;
--width)
WIDTH="$2"
shift # past argument
shift # past value
;;
--select)
SELECT="$2"
shift # past argument
shift # past value
;;
-v|--verbose)
VERBOSE=true
shift # past argument
;;
--default)
DEFAULT=YES
shift # past argument
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [[ -n $1 ]]; then
# parse pid
TARGET_PID=$(echo ${1}|awk -F "@" '{print $1}');
local targetIp=$(echo ${1}|awk -F "@|:" '{print $2}');
[[ "$targetIp" ]] && TARGET_IP=$targetIp
local telnetPort=$(echo ${1}|awk -F ":" '{print $2}');
[[ "$telnetPort" ]] && TELNET_PORT=$telnetPort
local httpPort=$(echo ${1}|awk -F ":" '{print $3}');
[[ "$httpPort" ]] && HTTP_PORT=$httpPort
fi
# check telnet port/http port
local telnetPortPid
local httpPortPid
local telnetPortOrDefault=$(getTelnetPortOrDefault)
local httpPortOrDefault=$(getHttpPortOrDefault)
if [[ $telnetPortOrDefault > 0 ]]; then
telnetPortPid=$(find_listen_port_process $telnetPortOrDefault)
if [ $telnetPortPid ]; then
echo "[INFO] Process $telnetPortPid already using port $telnetPortOrDefault"
fi
fi
if [[ $httpPortOrDefault > 0 ]]; then
httpPortPid=$(find_listen_port_process $httpPortOrDefault)
if [ $telnetPortPid ]; then
echo "[INFO] Process $httpPortPid already using port $httpPortOrDefault"
fi
fi
if [ -z ${REPO_MIRROR} ]; then
REPO_MIRROR="center"
# if timezone is +0800, set REPO_MIRROR to aliyun
if [[ -x "$(command -v date)" ]] && [[ $(date +%z) == "+0800" ]]; then
REPO_MIRROR="aliyun"
fi
fi
# try to find target pid by --select option
if [ -z ${TARGET_PID} ] && [ ${SELECT} ]; then
local IFS=$'\n'
CANDIDATES=($(call_jps | grep -v sun.tools.jps.Jps | grep "${SELECT}" | awk '{print $0}'))
if [ ${#CANDIDATES[@]} -eq 1 ]; then
TARGET_PID=`echo ${CANDIDATES[0]} | cut -d ' ' -f 1`
fi
fi
# check pid
if [ -z ${TARGET_PID} ]; then
# interactive mode
local IFS=$'\n'
CANDIDATES=($(call_jps | grep -v sun.tools.jps.Jps | awk '{print $0}'))
if [ ${#CANDIDATES[@]} -eq 0 ]; then
echo "Error: no available java process to attach."
return 1
fi
echo "Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER."
index=0
suggest=1
# auto select tomcat/pandora-boot process
for process in "${CANDIDATES[@]}"; do
index=$(($index+1))
if [ $(echo ${process} | grep -c org.apache.catalina.startup.Bootstrap) -eq 1 ] \
|| [ $(echo ${process} | grep -c com.taobao.pandora.boot.loader.SarLauncher) -eq 1 ]
then
suggest=${index}
break
fi
done
index=0
for process in "${CANDIDATES[@]}"; do
index=$(($index+1))
if [ ${index} -eq ${suggest} ]; then
echo "* [$index]: ${process}"
else
echo " [$index]: ${process}"
fi
done
read choice
if [ -z ${choice} ]; then
choice=${suggest}
fi
TARGET_PID=`echo ${CANDIDATES[$(($choice-1))]} | cut -d ' ' -f 1`
# check the process already using telnet port if equals to target pid
if [[ ($telnetPortPid) && ($TARGET_PID != $telnetPortPid) ]]; then
print_telnet_port_pid_error
exit 1
fi
if [[ ($httpPortPid) && ($TARGET_PID != $httpPortPid) ]]; then
echo "Target process $TARGET_PID is not the process using port $(getHttpPortOrDefault), you will connect to an unexpected process."
echo "1. Try to restart as.sh, select process $httpPortPid, shutdown it first with running the 'stop' command."
echo "2. Try to use different http port, for example: as.sh --telnet-port 9998 --http-port 9999"
exit 1
fi
elif [ -z ${TARGET_PID} ]; then
# batch mode is enabled, no interactive process selection.
echo "Illegal arguments, the <PID> is required." 1>&2
return 1
fi
}
# attach arthas to target jvm
attach_jvm()
{
local arthas_lib_dir=$1
# http://www.inonit.com/cygwin/faq/
if [ "${OS_TYPE}" = "Cygwin" ]; then
arthas_lib_dir=`cygpath -wp "$arthas_lib_dir"`
fi
echo "Attaching to ${TARGET_PID} using version ${1}..."
local java_command=("${JAVA_HOME}"/bin/java)
if [ "${BOOT_CLASSPATH}" ]; then
java_command+=("${BOOT_CLASSPATH}")
fi
local tempArgs=()
if [ "${TUNNEL_SERVER}" ]; then
tempArgs+=("-tunnel-server")
tempArgs+=("${TUNNEL_SERVER}")
fi
if [ "${AGENT_ID}" ]; then
tempArgs+=("-agent-id")
tempArgs+=("${AGENT_ID}")
fi
if [ "${STAT_URL}" ]; then
tempArgs+=("-stat-url")
tempArgs+=("${STAT_URL}")
fi
if [ "${APP_NAME}" ]; then
tempArgs+=("-app-name")
tempArgs+=("${APP_NAME}")
fi
if [ "${USERNAME}" ]; then
tempArgs+=("-username")
tempArgs+=("${USERNAME}")
fi
if [ "${PASSWORD}" ]; then
tempArgs+=("-password")
tempArgs+=("${PASSWORD}")
fi
if [ "${DISABLED_COMMANDS}" ]; then
tempArgs+=("-disabled-commands")
tempArgs+=("${DISABLED_COMMANDS}")
fi
if [ "${TARGET_IP}" ]; then
tempArgs+=("-target-ip")
tempArgs+=("${TARGET_IP}")
fi
if [ "${TELNET_PORT}" ]; then
tempArgs+=("-telnet-port")
tempArgs+=("${TELNET_PORT}")
fi
if [ "${HTTP_PORT}" ]; then
tempArgs+=("-http-port")
tempArgs+=("${HTTP_PORT}")
fi
if [ "${SESSION_TIMEOUT}" ]; then
tempArgs+=("-session-timeout")
tempArgs+=("${SESSION_TIMEOUT}")
fi
"${java_command[@]}" \
${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-core.jar" \
-pid ${TARGET_PID} \
"${tempArgs[@]}" \
-core "${arthas_lib_dir}/arthas-core.jar" \
-agent "${arthas_lib_dir}/arthas-agent.jar"
}
sanity_check() {
# only Linux/Mac support ps to find process, Cygwin/MinGw may fail.
if ([ "${OS_TYPE}" != "Linux" ] && [ "${OS_TYPE}" != "Mac" ]); then
return
fi
# 0 check whether the pid exist
local pid=$(ps -p ${TARGET_PID} -o pid= 2>&1 )
# get ps command exit code
local exitCode="$(ps -p ${TARGET_PID} -o pid= > /dev/null 2>&1; echo $?)"
# If ps exist code not 0, the TARGET_PID process maybe not exist or ps do not support -p options.
if [ "${exitCode}" != "0" ]; then
# if ps do not support -p or -o , ${pid} will be error message, just return
if [ -n "${pid}" ]; then
return
fi
fi
if [ -z ${pid} ]; then
exit_on_err 1 "The target pid (${TARGET_PID}) does not exist!"
fi
# 1 check the current user matches the process owner
local current_user=$(id -u -n)
# the last '=' after 'user' eliminates the column header
local target_user=$(ps -p "${TARGET_PID}" -o user=)
if [ "$current_user" != "$target_user" ]; then
echo "The current user ($current_user) does not match with the owner of process ${TARGET_PID} ($target_user)."
echo "To solve this, choose one of the following command:"
echo " 1) sudo su $target_user && ./as.sh"
echo " 2) sudo -u $target_user -EH ./as.sh"
exit_on_err 1
fi
}
port_pid_check() {
if [[ $(getTelnetPortOrDefault) > 0 ]]; then
local telnet_output
local find_process_status
# declare local var before var=$()
telnet_output=$(find_listen_port_process_by_client)
find_process_status=$?
#echo "find_process_status: $find_process_status"
#echo "telnet_output: $telnet_output"
#check return code
if [[ $find_process_status -eq $STATUS_EXEC_TIMEOUT ]]; then
print_telnet_port_used_error "detection timeout"
exit 1
elif [[ $find_process_status -eq $STATUS_EXEC_ERROR ]]; then
print_telnet_port_used_error "detection error"
exit 1
fi
if [[ -n $telnet_output ]]; then
# check JAVA_PID
telnetPortPid=$(echo "$telnet_output" | grep JAVA_PID | awk '{ print $2 }')
#echo "telnetPortPid: $telnetPortPid"
# check the process already using telnet port if equals to target pid
if [[ -n $telnetPortPid && ($TARGET_PID != $telnetPortPid) ]]; then
print_telnet_port_pid_error
exit 1
fi
fi
fi
}
print_telnet_port_pid_error() {
echo "[ERROR] The telnet port $(getTelnetPortOrDefault) is used by process $telnetPortPid instead of target process $TARGET_PID, you will connect to an unexpected process."
echo "[ERROR] 1. Try to restart as.sh, select process $telnetPortPid, shutdown it first with running the 'stop' command."
echo "[ERROR] 2. Try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 $(getTelnetPortOrDefault) -c \"stop\""
echo "[ERROR] 3. Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1"
}
print_telnet_port_used_error() {
local error_msg=$1
echo "[ERROR] The telnet port $(getTelnetPortOrDefault) is used, but process $error_msg, you will connect to an unexpected process."
echo "[ERROR] Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1"
}
# active console
# $1 : arthas_lib_dir
active_console()
{
local arthas_lib_dir=$1
# http://www.inonit.com/cygwin/faq/
if [ "${OS_TYPE}" = "Cygwin" ]; then
arthas_lib_dir=`cygpath -wp $arthas_lib_dir`
fi
if [ "${BATCH_MODE}" = "true" ]; then
local tempArgs=()
if [ "${HEIGHT}" ]; then
tempArgs+=("--height")
tempArgs+=("${HEIGHT}")
fi
if [ "${WIDTH}" ]; then
tempArgs+=("--width")
tempArgs+=("${WIDTH}")
fi
if [ "${COMMAND}" ] ; then
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \
$(getTargetIPOrDefault) \
$(getTelnetPortOrDefault) \
"${tempArgs[@]}" \
-c "${COMMAND}"
fi
if [ "${BATCH_FILE}" ] ; then
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \
$(getTargetIPOrDefault) \
$(getTelnetPortOrDefault) \
"${tempArgs[@]}" \
-f ${BATCH_FILE}
fi
elif type telnet 2>&1 >> /dev/null; then
# use telnet
if [[ $(command -v telnet) == *"system32"* ]] ; then
# Windows/system32/telnet.exe can not run in Cygwin/MinGw
echo "It seems that current bash is under Windows. $(command -v telnet) can not run under bash."
echo "Please start cmd.exe from Windows start menu, and then run telnet $(getTargetIPOrDefault) $(getTelnetPortOrDefault) to connect to target process."
echo "Or visit http://127.0.0.1:$(getHttpPortOrDefault) to connect to target process."
return 1
fi
echo "telnet connecting to arthas server... current timestamp is `date +%s`"
telnet $(getTargetIPOrDefault) $(getTelnetPortOrDefault)
else
echo "'telnet' is required." 1>&2
return 1
fi
}
# the main
main()
{
echo "Arthas script version: $ARTHAS_SCRIPT_VERSION"
check_permission
reset_for_env
parse_arguments "${@}" \
|| exit_on_err 1 "$(usage)"
# try to find arthas home from --use-version
if [[ (-z "${ARTHAS_HOME}") && (! -z "${USE_VERSION}") ]]; then
if [[ ! -d "${ARTHAS_LIB_DIR}/${USE_VERSION}/arthas" ]] ; then
update_if_necessary "${USE_VERSION}" || echo "update fail, ignore this update." 1>&2
fi
ARTHAS_HOME="${ARTHAS_LIB_DIR}/${USE_VERSION}/arthas"
fi
# try to set arthas home from as.sh directory
if [ -z "${ARTHAS_HOME}" ] ; then
[[ -a "${DIR}/arthas-core.jar" ]] \
&& [[ -a "${DIR}/arthas-agent.jar" ]] \
&& [[ -a "${DIR}/arthas-spy.jar" ]] \
&& ARTHAS_HOME="${DIR}"
fi
# try to find arthas under ~/.arthas/lib
if [ -z "${ARTHAS_HOME}" ] ; then
local remote_version=$(get_remote_version)
local arthas_local_version=$(get_local_version)
if $(version_gt $remote_version $arthas_local_version) ; then
update_if_necessary "${remote_version}" || echo "update fail, ignore this update." 1>&2
fi
local arthas_local_version=$(get_local_version)
ARTHAS_HOME="${ARTHAS_LIB_DIR}/${arthas_local_version}/arthas"
fi
echo "Arthas home: ${ARTHAS_HOME}"
if [ ! -d "${ARTHAS_HOME}" ] ; then
exit_on_err 1 "Arthas home is not a directory, please delete it and retry."
fi
sanity_check
port_pid_check
echo "Calculating attach execution time..."
time (attach_jvm "${ARTHAS_HOME}" || exit 1)
if [ $? -ne 0 ]; then
exit_on_err 1 "attach to target jvm (${TARGET_PID}) failed, check ${HOME}/logs/arthas/arthas.log or stderr of target jvm for any exceptions."
fi
echo "Attach success."
if [ ${ATTACH_ONLY} = false ]; then
active_console "${ARTHAS_HOME}"
fi
}
main "${@}"
\ No newline at end of file
#!/bin/bash
# define newest arthas's version
ARTHAS_VERSION=${project.version}
# define newest arthas's lib home
ARTHAS_LIB_HOME=${HOME}/.arthas/lib/${ARTHAS_VERSION}/arthas
# exit shell with err_code
# $1 : err_code
# $2 : err_msg
exit_on_err()
{
[[ ! -z "${2}" ]] && echo "${2}" 1>&2
exit ${1}
}
# install to local if necessary
if [[ ! -x ${ARTHAS_LIB_HOME} ]]; then
# install to local
mkdir -p ${ARTHAS_LIB_HOME} \
|| exit_on_err 1 "create target directory ${ARTHAS_LIB_HOME} failed."
# copy jar files
cp *.jar ${ARTHAS_LIB_HOME}/
# make it -x
chmod +x ./as.sh
fi
echo "install to local succeeded."
#! /bin/bash
# temp file of as.sh
TEMP_ARTHAS_FILE="./as.sh.$$"
# target file of as.sh
TARGET_ARTHAS_FILE="./as.sh"
# update timeout(sec)
SO_TIMEOUT=60
# default downloading url
ARTHAS_FILE_URL="https://arthas.aliyun.com/as.sh"
# exit shell with err_code
# $1 : err_code
# $2 : err_msg
exit_on_err()
{
[[ ! -z "${2}" ]] && echo "${2}" 1>&2
exit ${1}
}
# check permission to download && install
[[ ! -w ./ ]] && exit_on_err 1 "permission denied, target directory ./ was not writable."
if [[ $# -gt 1 ]] && [[ $1 = "--url" ]]; then
shift
ARTHAS_FILE_URL=$1
shift
fi
# download from aliyunos
echo "downloading... ${TEMP_ARTHAS_FILE}"
curl \
-sLk \
--connect-timeout ${SO_TIMEOUT} \
${ARTHAS_FILE_URL} \
-o ${TEMP_ARTHAS_FILE} \
|| exit_on_err 1 "download failed!"
# write or overwrite local file
rm -rf as.sh
mv ${TEMP_ARTHAS_FILE} ${TARGET_ARTHAS_FILE}
chmod +x ${TARGET_ARTHAS_FILE}
# done
echo "Arthas install succeeded."
#!/bin/sh
# jps.sh version 1.0.2
# there might be multiple java processes, e.g. log-agent
JPS_CMDS=($(ps aux | grep java | grep -v 'grep java' | awk '{print $11}' | sed -n 's/java$/jps/p'))
# find the first executable jps command
JPS_CMD=""
for jps in ${JPS_CMDS[@]}; do
if [ -x $jps ]; then
JPS_CMD=$jps
break
fi
done
if [ "$JPS_CMD" == "" ]; then
echo "No Java Process Found on this Machine."
exit 1
else
result=`$JPS_CMD -lmv | grep -v jps`
if [ "$result" == "" ]; then
ps aux | grep -E '^admin.*java.*' | grep -v grep | awk 'BEGIN{ORS=""}{print $2" ";for(j=NF;j>=12;j--){if(match($j, /^\-[a-zA-Z0-9]/)) {break;} } for(i=j+1;i<=NF;i++) {print $i" "} for(i=12;i<=j;i++) {print $i" "} print "\n" }'
else
echo "$result"
fi
fi
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>arthas-boot</artifactId>
<name>arthas-boot</name>
<dependencies>
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.middleware</groupId>
<artifactId>cli</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>arthas-boot</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>single</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.taobao.arthas.boot.Bootstrap</mainClass>
</manifest>
<manifestEntries>
<Created-By>core engine team, middleware group, alibaba inc.</Created-By>
<Specification-Title>${project.name}</Specification-Title>
<Specification-Version>${project.version}</Specification-Version>
<Implementation-Title>${project.name}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package com.taobao.arthas.boot;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_ERROR;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import com.taobao.arthas.common.AnsiLog;
import com.taobao.arthas.common.JavaVersionUtils;
import com.taobao.arthas.common.SocketUtils;
import com.taobao.arthas.common.UsageRender;
import com.taobao.middleware.cli.CLI;
import com.taobao.middleware.cli.CommandLine;
import com.taobao.middleware.cli.UsageMessageFormatter;
import com.taobao.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.CLIConfigurator;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Option;
import com.taobao.middleware.cli.annotations.Summary;
/**
* @author hengyunabc 2018-10-26
*
*/
@Name("arthas-boot")
@Summary("Bootstrap Arthas")
@Description("EXAMPLES:\n" + " java -jar arthas-boot.jar <pid>\n" + " java -jar arthas-boot.jar --target-ip 0.0.0.0\n"
+ " java -jar arthas-boot.jar --telnet-port 9999 --http-port -1\n"
+ " java -jar arthas-boot.jar --username admin --password <password>\n"
+ " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws' --app-name demoapp\n"
+ " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw\n"
+ " java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'\n"
+ " java -jar arthas-boot.jar -c 'sysprop; thread' <pid>\n"
+ " java -jar arthas-boot.jar -f batch.as <pid>\n"
+ " java -jar arthas-boot.jar --use-version 3.6.4\n"
+ " java -jar arthas-boot.jar --versions\n"
+ " java -jar arthas-boot.jar --select math-game\n"
+ " java -jar arthas-boot.jar --session-timeout 3600\n" + " java -jar arthas-boot.jar --attach-only\n"
+ " java -jar arthas-boot.jar --disabled-commands stop,dump\n"
+ " java -jar arthas-boot.jar --repo-mirror aliyun --use-http\n" + "WIKI:\n"
+ " https://arthas.aliyun.com/doc\n")
public class Bootstrap {
private static final int DEFAULT_TELNET_PORT = 3658;
private static final int DEFAULT_HTTP_PORT = 8563;
private static final String DEFAULT_TARGET_IP = "127.0.0.1";
private static File ARTHAS_LIB_DIR;
private boolean help = false;
private long pid = -1;
private String targetIp;
private Integer telnetPort;
private Integer httpPort;
/**
* @see com.taobao.arthas.core.config.Configure#DEFAULT_SESSION_TIMEOUT_SECONDS
*/
private Long sessionTimeout;
private Integer height = null;
private Integer width = null;
private boolean verbose = false;
/**
* <pre>
* The directory contains arthas-core.jar/arthas-client.jar/arthas-spy.jar.
* 1. When use-version is not empty, try to find arthas home under ~/.arthas/lib
* 2. Try set the directory where arthas-boot.jar is located to arthas home
* 3. Try to download from remote repo
* </pre>
*/
private String arthasHome;
/**
* under ~/.arthas/lib
*/
private String useVersion;
/**
* list local and remote versions
*/
private boolean versions;
/**
* download from remo repository. if timezone is +0800, default value is 'aliyun', else is 'center'.
*/
private String repoMirror;
/**
* enforce use http to download arthas. default use https
*/
private boolean useHttp = false;
private boolean attachOnly = false;
private String command;
private String batchFile;
private String tunnelServer;
private String agentId;
private String appName;
private String username;
private String password;
private String statUrl;
private String select;
private String disabledCommands;
static {
String arthasLibDirEnv = System.getenv("ARTHAS_LIB_DIR");
if (arthasLibDirEnv != null) {
ARTHAS_LIB_DIR = new File(arthasLibDirEnv);
} else {
ARTHAS_LIB_DIR = new File(
System.getProperty("user.home") + File.separator + ".arthas" + File.separator + "lib");
}
try {
ARTHAS_LIB_DIR.mkdirs();
} catch (Throwable t) {
//ignore
}
if (!ARTHAS_LIB_DIR.exists()) {
// try to set a temp directory
ARTHAS_LIB_DIR = new File(System.getProperty("java.io.tmpdir") + File.separator + ".arthas" + File.separator + "lib");
try {
ARTHAS_LIB_DIR.mkdirs();
} catch (Throwable e) {
// ignore
}
}
if (!ARTHAS_LIB_DIR.exists()) {
System.err.println("Can not find directory to save arthas lib. please try to set user home by -Duser.home=");
}
}
@Argument(argName = "pid", index = 0, required = false)
@Description("Target pid")
public void setPid(long pid) {
this.pid = pid;
}
@Option(shortName = "h", longName = "help", flag = true)
@Description("Print usage")
public void setHelp(boolean help) {
this.help = help;
}
@Option(longName = "target-ip")
@Description("The target jvm listen ip, default 127.0.0.1")
public void setTargetIp(String targetIp) {
this.targetIp = targetIp;
}
@Option(longName = "telnet-port")
@Description("The target jvm listen telnet port, default 3658")
public void setTelnetPort(int telnetPort) {
this.telnetPort = telnetPort;
}
@Option(longName = "http-port")
@Description("The target jvm listen http port, default 8563")
public void setHttpPort(int httpPort) {
this.httpPort = httpPort;
}
@Option(longName = "session-timeout")
@Description("The session timeout seconds, default 1800 (30min)")
public void setSessionTimeout(Long sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
@Option(longName = "arthas-home")
@Description("The arthas home")
public void setArthasHome(String arthasHome) {
this.arthasHome = arthasHome;
}
@Option(longName = "use-version")
@Description("Use special version arthas")
public void setUseVersion(String useVersion) {
this.useVersion = useVersion;
}
@Option(longName = "repo-mirror")
@Description("Use special remote repository mirror, value is center/aliyun or http repo url.")
public void setRepoMirror(String repoMirror) {
this.repoMirror = repoMirror;
}
@Option(longName = "versions", flag = true)
@Description("List local and remote arthas versions")
public void setVersions(boolean versions) {
this.versions = versions;
}
@Option(longName = "use-http", flag = true)
@Description("Enforce use http to download, default use https")
public void setuseHttp(boolean useHttp) {
this.useHttp = useHttp;
}
@Option(longName = "attach-only", flag = true)
@Description("Attach target process only, do not connect")
public void setAttachOnly(boolean attachOnly) {
this.attachOnly = attachOnly;
}
@Option(shortName = "c", longName = "command")
@Description("Command to execute, multiple commands separated by ;")
public void setCommand(String command) {
this.command = command;
}
@Option(shortName = "f", longName = "batch-file")
@Description("The batch file to execute")
public void setBatchFile(String batchFile) {
this.batchFile = batchFile;
}
@Option(longName = "height")
@Description("arthas-client terminal height")
public void setHeight(int height) {
this.height = height;
}
@Option(longName = "width")
@Description("arthas-client terminal width")
public void setWidth(int width) {
this.width = width;
}
@Option(shortName = "v", longName = "verbose", flag = true)
@Description("Verbose, print debug info.")
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
@Option(longName = "tunnel-server")
@Description("The tunnel server url")
public void setTunnelServer(String tunnelServer) {
this.tunnelServer = tunnelServer;
}
@Option(longName = "agent-id")
@Description("The agent id register to tunnel server")
public void setAgentId(String agentId) {
this.agentId = agentId;
}
@Option(longName = "app-name")
@Description("The app name")
public void setAppName(String appName) {
this.appName = appName;
}
@Option(longName = "username")
@Description("The username")
public void setUsername(String username) {
this.username = username;
}
@Option(longName = "password")
@Description("The password")
public void setPassword(String password) {
this.password = password;
}
@Option(longName = "stat-url")
@Description("The report stat url")
public void setStatUrl(String statUrl) {
this.statUrl = statUrl;
}
@Option(longName = "select")
@Description("select target process by classname or JARfilename")
public void setSelect(String select) {
this.select = select;
}
@Option(longName = "disabled-commands")
@Description("disable some commands ")
public void setDisabledCommands(String disabledCommands) {
this.disabledCommands = disabledCommands;
}
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException,
ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Package bootstrapPackage = Bootstrap.class.getPackage();
if (bootstrapPackage != null) {
String arthasBootVersion = bootstrapPackage.getImplementationVersion();
if (arthasBootVersion != null) {
AnsiLog.info("arthas-boot version: " + arthasBootVersion);
}
}
Bootstrap bootstrap = new Bootstrap();
CLI cli = CLIConfigurator.define(Bootstrap.class);
CommandLine commandLine = cli.parse(Arrays.asList(args));
try {
CLIConfigurator.inject(commandLine, bootstrap);
} catch (Throwable e) {
e.printStackTrace();
System.out.println(usage(cli));
System.exit(1);
}
if (bootstrap.isVerbose()) {
AnsiLog.level(Level.ALL);
}
if (bootstrap.isHelp()) {
System.out.println(usage(cli));
System.exit(0);
}
if (bootstrap.getRepoMirror() == null || bootstrap.getRepoMirror().trim().isEmpty()) {
bootstrap.setRepoMirror("center");
// if timezone is +0800, default repo mirror is aliyun
if (TimeUnit.MILLISECONDS.toHours(TimeZone.getDefault().getOffset(System.currentTimeMillis())) == 8) {
bootstrap.setRepoMirror("aliyun");
}
}
AnsiLog.debug("Repo mirror:" + bootstrap.getRepoMirror());
if (bootstrap.isVersions()) {
System.out.println(UsageRender.render(listVersions()));
System.exit(0);
}
if (JavaVersionUtils.isJava6() || JavaVersionUtils.isJava7()) {
bootstrap.setuseHttp(true);
AnsiLog.debug("Java version is {}, only support http, set useHttp to true.",
JavaVersionUtils.javaVersionStr());
}
// check telnet/http port
long telnetPortPid = -1;
long httpPortPid = -1;
if (bootstrap.getTelnetPortOrDefault() > 0) {
telnetPortPid = SocketUtils.findTcpListenProcess(bootstrap.getTelnetPortOrDefault());
if (telnetPortPid > 0) {
AnsiLog.info("Process {} already using port {}", telnetPortPid, bootstrap.getTelnetPortOrDefault());
}
}
if (bootstrap.getHttpPortOrDefault() > 0) {
httpPortPid = SocketUtils.findTcpListenProcess(bootstrap.getHttpPortOrDefault());
if (httpPortPid > 0) {
AnsiLog.info("Process {} already using port {}", httpPortPid, bootstrap.getHttpPortOrDefault());
}
}
long pid = bootstrap.getPid();
// select pid
if (pid < 0) {
try {
pid = ProcessUtils.select(bootstrap.isVerbose(), telnetPortPid, bootstrap.getSelect());
} catch (InputMismatchException e) {
System.out.println("Please input an integer to select pid.");
System.exit(1);
}
if (pid < 0) {
System.out.println("Please select an available pid.");
System.exit(1);
}
}
checkTelnetPortPid(bootstrap, telnetPortPid, pid);
if (httpPortPid > 0 && pid != httpPortPid) {
AnsiLog.error("Target process {} is not the process using port {}, you will connect to an unexpected process.",
pid, bootstrap.getHttpPortOrDefault());
AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.",
httpPortPid);
AnsiLog.error("2. Or try to use different http port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port 9999", httpPortPid);
System.exit(1);
}
// find arthas home
File arthasHomeDir = null;
if (bootstrap.getArthasHome() != null) {
verifyArthasHome(bootstrap.getArthasHome());
arthasHomeDir = new File(bootstrap.getArthasHome());
}
if (arthasHomeDir == null && bootstrap.getUseVersion() != null) {
// try to find from ~/.arthas/lib
File specialVersionDir = new File(System.getProperty("user.home"), ".arthas" + File.separator + "lib"
+ File.separator + bootstrap.getUseVersion() + File.separator + "arthas");
if (!specialVersionDir.exists()) {
// try to download arthas from remote server.
DownloadUtils.downArthasPackaging(bootstrap.getRepoMirror(), bootstrap.isuseHttp(),
bootstrap.getUseVersion(), ARTHAS_LIB_DIR.getAbsolutePath());
}
verifyArthasHome(specialVersionDir.getAbsolutePath());
arthasHomeDir = specialVersionDir;
}
// Try set the directory where arthas-boot.jar is located to arhtas home
if (arthasHomeDir == null) {
CodeSource codeSource = Bootstrap.class.getProtectionDomain().getCodeSource();
if (codeSource != null) {
try {
// https://stackoverflow.com/a/17870390
File bootJarPath = new File(codeSource.getLocation().toURI().getSchemeSpecificPart());
verifyArthasHome(bootJarPath.getParent());
arthasHomeDir = bootJarPath.getParentFile();
} catch (Throwable e) {
// ignore
}
}
}
// try to download from remote server
if (arthasHomeDir == null) {
boolean checkFile = ARTHAS_LIB_DIR.exists() || ARTHAS_LIB_DIR.mkdirs();
if(!checkFile){
AnsiLog.error("cannot create directory {}: maybe permission denied", ARTHAS_LIB_DIR.getAbsolutePath());
System.exit(1);
}
/**
* <pre>
* 1. get local latest version
* 2. get remote latest version
* 3. compare two version
* </pre>
*/
List<String> versionList = listNames(ARTHAS_LIB_DIR);
Collections.sort(versionList);
String localLastestVersion = null;
if (!versionList.isEmpty()) {
localLastestVersion = versionList.get(versionList.size() - 1);
}
String remoteLastestVersion = DownloadUtils.readLatestReleaseVersion();
boolean needDownload = false;
if (localLastestVersion == null) {
if (remoteLastestVersion == null) {
// exit
AnsiLog.error("Can not find Arthas under local: {} and remote repo mirror: {}", ARTHAS_LIB_DIR,
bootstrap.getRepoMirror());
AnsiLog.error(
"Unable to download arthas from remote server, please download the full package according to wiki: https://github.com/alibaba/arthas");
System.exit(1);
} else {
needDownload = true;
}
} else {
if (remoteLastestVersion != null) {
if (localLastestVersion.compareTo(remoteLastestVersion) < 0) {
AnsiLog.info("local lastest version: {}, remote lastest version: {}, try to download from remote.",
localLastestVersion, remoteLastestVersion);
needDownload = true;
}
}
}
if (needDownload) {
// try to download arthas from remote server.
DownloadUtils.downArthasPackaging(bootstrap.getRepoMirror(), bootstrap.isuseHttp(),
remoteLastestVersion, ARTHAS_LIB_DIR.getAbsolutePath());
localLastestVersion = remoteLastestVersion;
}
// get the latest version
arthasHomeDir = new File(ARTHAS_LIB_DIR, localLastestVersion + File.separator + "arthas");
}
verifyArthasHome(arthasHomeDir.getAbsolutePath());
AnsiLog.info("arthas home: " + arthasHomeDir);
if (telnetPortPid > 0 && pid == telnetPortPid) {
AnsiLog.info("The target process already listen port {}, skip attach.", bootstrap.getTelnetPortOrDefault());
} else {
//double check telnet port and pid before attach
telnetPortPid = findProcessByTelnetClient(arthasHomeDir.getAbsolutePath(), bootstrap.getTelnetPortOrDefault());
checkTelnetPortPid(bootstrap, telnetPortPid, pid);
// start arthas-core.jar
List<String> attachArgs = new ArrayList<String>();
attachArgs.add("-jar");
attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath());
attachArgs.add("-pid");
attachArgs.add("" + pid);
if (bootstrap.getTargetIp() != null) {
attachArgs.add("-target-ip");
attachArgs.add(bootstrap.getTargetIp());
}
if (bootstrap.getTelnetPort() != null) {
attachArgs.add("-telnet-port");
attachArgs.add("" + bootstrap.getTelnetPort());
}
if (bootstrap.getHttpPort() != null) {
attachArgs.add("-http-port");
attachArgs.add("" + bootstrap.getHttpPort());
}
attachArgs.add("-core");
attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath());
attachArgs.add("-agent");
attachArgs.add(new File(arthasHomeDir, "arthas-agent.jar").getAbsolutePath());
if (bootstrap.getSessionTimeout() != null) {
attachArgs.add("-session-timeout");
attachArgs.add("" + bootstrap.getSessionTimeout());
}
if (bootstrap.getAppName() != null) {
attachArgs.add("-app-name");
attachArgs.add(bootstrap.getAppName());
}
if (bootstrap.getUsername() != null) {
attachArgs.add("-username");
attachArgs.add(bootstrap.getUsername());
}
if (bootstrap.getPassword() != null) {
attachArgs.add("-password");
attachArgs.add(bootstrap.getPassword());
}
if (bootstrap.getTunnelServer() != null) {
attachArgs.add("-tunnel-server");
attachArgs.add(bootstrap.getTunnelServer());
}
if (bootstrap.getAgentId() != null) {
attachArgs.add("-agent-id");
attachArgs.add(bootstrap.getAgentId());
}
if (bootstrap.getStatUrl() != null) {
attachArgs.add("-stat-url");
attachArgs.add(bootstrap.getStatUrl());
}
if (bootstrap.getDisabledCommands() != null){
attachArgs.add("-disabled-commands");
attachArgs.add(bootstrap.getDisabledCommands());
}
AnsiLog.info("Try to attach process " + pid);
AnsiLog.debug("Start arthas-core.jar args: " + attachArgs);
ProcessUtils.startArthasCore(pid, attachArgs);
AnsiLog.info("Attach process {} success.", pid);
}
if (bootstrap.isAttachOnly()) {
System.exit(0);
}
// start java telnet client
// find arthas-client.jar
URLClassLoader classLoader = new URLClassLoader(
new URL[] { new File(arthasHomeDir, "arthas-client.jar").toURI().toURL() });
Class<?> telnetConsoleClas = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole");
Method mainMethod = telnetConsoleClas.getMethod("main", String[].class);
List<String> telnetArgs = new ArrayList<String>();
if (bootstrap.getCommand() != null) {
telnetArgs.add("-c");
telnetArgs.add(bootstrap.getCommand());
}
if (bootstrap.getBatchFile() != null) {
telnetArgs.add("-f");
telnetArgs.add(bootstrap.getBatchFile());
}
if (bootstrap.getHeight() != null) {
telnetArgs.add("--height");
telnetArgs.add("" + bootstrap.getHeight());
}
if (bootstrap.getWidth() != null) {
telnetArgs.add("--width");
telnetArgs.add("" + bootstrap.getWidth());
}
// telnet port ,ip
telnetArgs.add(bootstrap.getTargetIpOrDefault());
telnetArgs.add("" + bootstrap.getTelnetPortOrDefault());
AnsiLog.info("arthas-client connect {} {}", bootstrap.getTargetIpOrDefault(), bootstrap.getTelnetPortOrDefault());
AnsiLog.debug("Start arthas-client.jar args: " + telnetArgs);
// fix https://github.com/alibaba/arthas/issues/833
Thread.currentThread().setContextClassLoader(classLoader);
mainMethod.invoke(null, new Object[] { telnetArgs.toArray(new String[0]) });
}
private static void checkTelnetPortPid(Bootstrap bootstrap, long telnetPortPid, long targetPid) {
if (telnetPortPid > 0 && targetPid != telnetPortPid) {
AnsiLog.error("The telnet port {} is used by process {} instead of target process {}, you will connect to an unexpected process.",
bootstrap.getTelnetPortOrDefault(), telnetPortPid, targetPid);
AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.",
telnetPortPid);
AnsiLog.error("2. Or try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 {} -c \"stop\"", bootstrap.getTelnetPortOrDefault());
AnsiLog.error("3. Or try to use different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1");
System.exit(1);
}
}
private static long findProcessByTelnetClient(String arthasHomeDir, int telnetPort) {
// start java telnet client
List<String> telnetArgs = new ArrayList<String>();
telnetArgs.add("-c");
telnetArgs.add("session");
telnetArgs.add("--execution-timeout");
telnetArgs.add("2000");
// telnet port ,ip
telnetArgs.add("127.0.0.1");
telnetArgs.add("" + telnetPort);
try {
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
String error = null;
int status = ProcessUtils.startArthasClient(arthasHomeDir, telnetArgs, out);
if (status == STATUS_EXEC_TIMEOUT) {
error = "detection timeout";
} else if (status == STATUS_EXEC_ERROR) {
error = "detection error";
AnsiLog.error("process status: {}", status);
AnsiLog.error("process output: {}", out.toString());
} else {
// ignore connect error
}
if (error != null) {
AnsiLog.error("The telnet port {} is used, but process {}, you will connect to an unexpected process.", telnetPort, error);
AnsiLog.error("Try to use a different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1");
System.exit(1);
}
//parse output, find java pid
String output = out.toString("UTF-8");
String javaPidLine = null;
Scanner scanner = new Scanner(output);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.contains("JAVA_PID")) {
javaPidLine = line;
break;
}
}
if (javaPidLine != null) {
// JAVA_PID 10473
try {
String[] strs = javaPidLine.split("JAVA_PID");
if (strs.length > 1) {
return Long.parseLong(strs[strs.length - 1].trim());
}
} catch (NumberFormatException e) {
// ignore
}
}
} catch (Throwable ex) {
AnsiLog.error("Detection telnet port error");
AnsiLog.error(ex);
}
return -1;
}
private static String listVersions() {
StringBuilder result = new StringBuilder(1024);
List<String> versionList = listNames(ARTHAS_LIB_DIR);
Collections.sort(versionList);
result.append("Local versions:\n");
for (String version : versionList) {
result.append(" ").append(version).append('\n');
}
result.append("Remote versions:\n");
List<String> remoteVersions = DownloadUtils.readRemoteVersions();
if (remoteVersions != null) {
Collections.reverse(remoteVersions);
for (String version : remoteVersions) {
result.append(" " + version).append('\n');
}
} else {
result.append(" unknown\n");
}
return result.toString();
}
private static List<String> listNames(File dir) {
List<String> names = new ArrayList<String>();
if (!dir.exists()) {
return names;
}
File[] files = dir.listFiles();
if (files == null) {
return names;
}
for (File file : files) {
String name = file.getName();
if (name.startsWith(".") || file.isFile()) {
continue;
}
names.add(name);
}
return names;
}
private static void verifyArthasHome(String arthasHome) {
File home = new File(arthasHome);
if (home.isDirectory()) {
String[] fileList = { "arthas-core.jar", "arthas-agent.jar", "arthas-spy.jar" };
for (String fileName : fileList) {
if (!new File(home, fileName).exists()) {
throw new IllegalArgumentException(
fileName + " do not exist, arthas home: " + home.getAbsolutePath());
}
}
return;
}
throw new IllegalArgumentException("illegal arthas home: " + home.getAbsolutePath());
}
private static String usage(CLI cli) {
StringBuilder usageStringBuilder = new StringBuilder();
UsageMessageFormatter usageMessageFormatter = new UsageMessageFormatter();
usageMessageFormatter.setOptionComparator(null);
cli.usage(usageStringBuilder, usageMessageFormatter);
return UsageRender.render(usageStringBuilder.toString());
}
public String getArthasHome() {
return arthasHome;
}
public String getUseVersion() {
return useVersion;
}
public String getRepoMirror() {
return repoMirror;
}
public boolean isuseHttp() {
return useHttp;
}
public String getTargetIp() {
return targetIp;
}
public String getTargetIpOrDefault() {
if (this.targetIp == null) {
return DEFAULT_TARGET_IP;
} else {
return this.targetIp;
}
}
public Integer getTelnetPort() {
return telnetPort;
}
public int getTelnetPortOrDefault() {
if (this.telnetPort == null) {
return DEFAULT_TELNET_PORT;
} else {
return this.telnetPort;
}
}
public Integer getHttpPort() {
return httpPort;
}
public int getHttpPortOrDefault() {
if (this.httpPort == null) {
return DEFAULT_HTTP_PORT;
} else {
return this.httpPort;
}
}
public String getCommand() {
return command;
}
public String getBatchFile() {
return batchFile;
}
public boolean isAttachOnly() {
return attachOnly;
}
public long getPid() {
return pid;
}
public boolean isHelp() {
return help;
}
public Long getSessionTimeout() {
return sessionTimeout;
}
public boolean isVerbose() {
return verbose;
}
public boolean isVersions() {
return versions;
}
public Integer getHeight() {
return height;
}
public Integer getWidth() {
return width;
}
public String getTunnelServer() {
return tunnelServer;
}
public String getAgentId() {
return agentId;
}
public String getAppName() {
return appName;
}
public String getStatUrl() {
return statUrl;
}
public String getSelect() {
return select;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getDisabledCommands() {
return disabledCommands;
}
}
package com.taobao.arthas.boot;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import com.taobao.arthas.common.AnsiLog;
import com.taobao.arthas.common.IOUtils;
/**
*
* @author hengyunabc 2018-11-06
*
*/
public class DownloadUtils {
private static final String ARTHAS_VERSIONS_URL = "https://arthas.aliyun.com/api/versions";
private static final String ARTHAS_LATEST_VERSIONS_URL = "https://arthas.aliyun.com/api/latest_version";
private static final String ARTHAS_DOWNLOAD_URL = "https://arthas.aliyun.com/download/${VERSION}?mirror=${REPO}";
private static final int CONNECTION_TIMEOUT = 3000;
public static String readLatestReleaseVersion() {
InputStream inputStream = null;
try {
URLConnection connection = openURLConnection(ARTHAS_LATEST_VERSIONS_URL);
inputStream = connection.getInputStream();
return IOUtils.toString(inputStream).trim();
} catch (Throwable t) {
AnsiLog.error("Can not read arthas version from: " + ARTHAS_LATEST_VERSIONS_URL);
AnsiLog.debug(t);
} finally {
IOUtils.close(inputStream);
}
return null;
}
public static List<String> readRemoteVersions() {
InputStream inputStream = null;
try {
URLConnection connection = openURLConnection(ARTHAS_VERSIONS_URL);
inputStream = connection.getInputStream();
String versionsStr = IOUtils.toString(inputStream);
String[] versions = versionsStr.split("\r\n");
ArrayList<String> result = new ArrayList<String>();
for (String version : versions) {
result.add(version.trim());
}
return result;
} catch (Throwable t) {
AnsiLog.error("Can not read arthas versions from: " + ARTHAS_VERSIONS_URL);
AnsiLog.debug(t);
} finally {
IOUtils.close(inputStream);
}
return null;
}
private static String getRepoUrl(String repoUrl, boolean http) {
if (repoUrl.endsWith("/")) {
repoUrl = repoUrl.substring(0, repoUrl.length() - 1);
}
if (http && repoUrl.startsWith("https")) {
repoUrl = "http" + repoUrl.substring("https".length());
}
return repoUrl;
}
public static void downArthasPackaging(String repoMirror, boolean http, String arthasVersion, String savePath)
throws IOException {
String repoUrl = getRepoUrl(ARTHAS_DOWNLOAD_URL, http);
File unzipDir = new File(savePath, arthasVersion + File.separator + "arthas");
File tempFile = File.createTempFile("arthas", "arthas");
AnsiLog.debug("Arthas download temp file: " + tempFile.getAbsolutePath());
String remoteDownloadUrl = repoUrl.replace("${REPO}", repoMirror).replace("${VERSION}", arthasVersion);
AnsiLog.info("Start download arthas from remote server: " + remoteDownloadUrl);
saveUrl(tempFile.getAbsolutePath(), remoteDownloadUrl, true);
AnsiLog.info("Download arthas success.");
IOUtils.unzip(tempFile.getAbsolutePath(), unzipDir.getAbsolutePath());
}
private static void saveUrl(final String filename, final String urlString, boolean printProgress)
throws IOException {
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
URLConnection connection = openURLConnection(urlString);
in = new BufferedInputStream(connection.getInputStream());
List<String> values = connection.getHeaderFields().get("Content-Length");
int fileSize = 0;
if (values != null && !values.isEmpty()) {
String contentLength = values.get(0);
if (contentLength != null) {
// parse the length into an integer...
fileSize = Integer.parseInt(contentLength);
}
}
fout = new FileOutputStream(filename);
final byte[] data = new byte[1024 * 1024];
int totalCount = 0;
int count;
long lastPrintTime = System.currentTimeMillis();
while ((count = in.read(data, 0, 1024 * 1024)) != -1) {
totalCount += count;
if (printProgress) {
long now = System.currentTimeMillis();
if (now - lastPrintTime > 1000) {
AnsiLog.info("File size: {}, downloaded size: {}, downloading ...", formatFileSize(fileSize),
formatFileSize(totalCount));
lastPrintTime = now;
}
}
fout.write(data, 0, count);
}
} catch (javax.net.ssl.SSLException e) {
AnsiLog.error("TLS connect error, please try to add --use-http argument.");
AnsiLog.error("URL: " + urlString);
AnsiLog.error(e);
} finally {
IOUtils.close(in);
IOUtils.close(fout);
}
}
/**
* support redirect
*
* @param url
* @return
* @throws MalformedURLException
* @throws IOException
*/
private static URLConnection openURLConnection(String url) throws MalformedURLException, IOException {
URLConnection connection = new URL(url).openConnection();
if (connection instanceof HttpURLConnection) {
connection.setConnectTimeout(CONNECTION_TIMEOUT);
// normally, 3xx is redirect
int status = ((HttpURLConnection) connection).getResponseCode();
if (status != HttpURLConnection.HTTP_OK) {
if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER) {
String newUrl = connection.getHeaderField("Location");
AnsiLog.debug("Try to open url: {}, redirect to: {}", url, newUrl);
return openURLConnection(newUrl);
}
}
}
return connection;
}
private static String formatFileSize(long size) {
String hrSize;
double b = size;
double k = size / 1024.0;
double m = ((size / 1024.0) / 1024.0);
double g = (((size / 1024.0) / 1024.0) / 1024.0);
double t = ((((size / 1024.0) / 1024.0) / 1024.0) / 1024.0);
DecimalFormat dec = new DecimalFormat("0.00");
if (t > 1) {
hrSize = dec.format(t).concat(" TB");
} else if (g > 1) {
hrSize = dec.format(g).concat(" GB");
} else if (m > 1) {
hrSize = dec.format(m).concat(" MB");
} else if (k > 1) {
hrSize = dec.format(k).concat(" KB");
} else {
hrSize = dec.format(b).concat(" Bytes");
}
return hrSize;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment