Skip to content

Installer: try to clean up old library files at the end of installation with out affecting the rest of a successful install - #7649

Merged
michaelDCurran merged 14 commits into
masterfrom
fixInstaller
Oct 25, 2017
Merged

Installer: try to clean up old library files at the end of installation with out affecting the rest of a successful install#7649
michaelDCurran merged 14 commits into
masterfrom
fixInstaller

Conversation

@michaelDCurran

@michaelDCurran michaelDCurran commented Oct 9, 2017

Copy link
Copy Markdown
Member

Link to issue number:

Fixes #7616
Fixes #7639

Summary of the issue:

With the merging of #7535 (which causes NVDA to now store libs in a version-specific directory), NVDA updates were constantly failing for certain users.
One or more of these users seemed to be running some kind of Intell security software which would occasionally lock files.
In most situations though, the majority of users were not experiencing the failing updates.
However, #7535 did introduce two specific mistakes. these were:

  1. logHandler did not look in the right path for nvdaHelperRemote in order to do remote logging from nvda_slave. This meant that we were no longer getting any logging from the installer.
  2. Files marked for deletion on reboot were never actually getting deleted as the directory they were in may also have been renamed and marked for delete on reboot, thus invalidating the path to the first lot of marked files. When the directory itself was going to be deleted on reboot, it still contained files and therefore Windows refuzed to delete it.
  3. It seems on some systems that if there are locked files in a directory, although you can rename the locked files, you can't rename the directory the locked files are in. Ensure IAccessible2 remains available in Firefox after restarting NVDA on Windows 10 Creaters update, register ISimpleDOM proxy to allow math in Google Chrome without Firefox installed, and Allow the user to get back a virtualBuffer when restarting NVDA with a Firefox document in focus #7535 was trying to rename these directories for delete on reboot.

Description of how this pull request fixes the issue:

Fix logging

logHandler now looks for nvdaHelperRemote in its version-specific directory, allowing logging to work from nvda_slave again. It also fails much earlier now if that dll cannot be found.

Old lib files are deleted only at the very end

Rather than deleting old library files at the beginning of the installation (which meant if this did introduce an error, the rest of the install would fail), instead try to delete them at the very end.
Also, if one of these files fails to be deleted, don't treet this as a hard error, only log a warning. The installer next time it is run can try and get rid of them again.

Testing performed:

Multiple NVDA updates on Windows 10 and Windows 7, with reboots. the updates succeeed, and all locked files are removed on reboot.
This also included performing the update with the old copy of NVDA still running on another session on the machine. The installer still successfully installed the new copy.

Comment thread source/installer.py Outdated
This uses Windows' MoveFileEx (either unicode or ascii depending on the given path) and also prepends'\\?\' to allow for long file names.
"""
MoveFileEx=windll.kernel32.MoveFileExW if isinstance(path,unicode) else windll.kernel32.MoveFileExA
return MoveFileEx("\\\\?\\"+path,None,4)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you replace the 4 with something like MOVEFILE_DELAY_UNTIL_REBOOT

Comment thread source/installer.py Outdated
def copyFile(sourceFilePath,destFilePath):
"""
Copies the file at sourcePath to destPath.
This uses Windows' CopyFile and prepends'\\?\' to allow for long file names.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the return value mean?

Comment thread source/installer.py Outdated
def deleteFileOnReboot(path):
"""
Marks a file for delete on reboot.
This uses Windows' MoveFileEx (either unicode or ascii depending on the given path) and also prepends'\\?\' to allow for long file names.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the type/meaning of the return value?

Comment thread source/logHandler.py Outdated
h=ctypes.windll.kernel32.LoadLibraryExW(os.path.abspath(ur"lib\nvdaHelperRemote.dll"),0,0x8)
self._remoteLib=ctypes.WinDLL("nvdaHelperRemote",handle=h) if h else None
path=os.path.abspath(os.path.join(u"lib",versionInfo.version,u"nvdaHelperRemote.dll"))
h=ctypes.windll.kernel32.LoadLibraryExW(path,0,0x8)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace 0x8 with something like LOAD_WITH_ALTERED_SEARCH_PATH

@Brian1Gaff

Brian1Gaff commented Oct 9, 2017 via email

Copy link
Copy Markdown

@michaelDCurran

Copy link
Copy Markdown
Member Author

Backed out of next. Multiple people were seeing problems. Perhaps this is simply a timing issue. The older installer code took more time trying to remove the first lot of files and therefore the old NVDA had enough time to fully exit or something. Very very strnage.

@michaelDCurran

Copy link
Copy Markdown
Member Author

At very least we need to take the logging fixes from this PR (assuming that we keep #7535).

michaelDCurran added a commit that referenced this pull request Oct 18, 2017
@michaelDCurran michaelDCurran changed the title Make installer handle more situations of locked files and add more logging Installer: try to clean up old library files at the end of installation with out affecting the rest of a successful install Oct 18, 2017
@michaelDCurran

Copy link
Copy Markdown
Member Author

This pr is now much les drastic, in that old lib files are only removed at the very end of the instllation, and no rewriting of other installer code such as tryRemovefile or trycopyFile exists in this pr now. thus, the rhythm and logic of the install is exactly the same as NVDA 2017.3 except for removing of old lib files at the very end. If this part fails, it is not a hard error.

@michaelDCurran

Copy link
Copy Markdown
Member Author

This has also been incubated in Next again for further testing of Next snapshots by Brian1Gaff and others. Testing Master is not necessary at this stage as the change have not yet reached that branch.

michaelDCurran added a commit that referenced this pull request Oct 18, 2017
@LeonarddeR

Copy link
Copy Markdown
Collaborator

May I ask why these changes have been incubated into Next without review?

@michaelDCurran

michaelDCurran commented Oct 19, 2017 via email

Copy link
Copy Markdown
Member Author

@Brian1Gaff

Brian1Gaff commented Oct 19, 2017 via email

Copy link
Copy Markdown

@Mary5958

Copy link
Copy Markdown
Contributor

Today I could "finally" reproduce it also on Windows 10; first while updating to the latest next, then also when doing a fresh install after a complete uninstall of the previous version and even removing the user data if that would make any difference.

INFO - main (21:13:29.977):
Starting NVDA
INFO - core.main (21:13:32.641):
Config dir: C:\Users\Martina\AppData\Local\Temp\nsk316.tmp\app\userConfig
INFO - config.ConfigManager._loadConfig (21:13:32.641):
Loading config: .\userConfig\nvda.ini
INFO - core.main (21:13:32.904):
NVDA version next-14538,68978508
INFO - core.main (21:13:32.904):
Using Windows version 10.0.15063 workstation
INFO - core.main (21:13:32.904):
Using Python version 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:42:59) [MSC v.1500 32 bit (Intel)]
INFO - core.main (21:13:32.904):
Using comtypes version 0.6.2
INFO - synthDrivers.espeak.SynthDriver.init (21:13:34.642):
Using eSpeak NG version 1.49.1 dev
INFO - speechDictHandler.dictFormatUpgrade._doSynthVoiceDictBackupAndMove (21:13:34.709):
Upgrading voice dictionaries for espeak
INFO - synthDriverHandler.setSynth (21:13:34.819):
Loaded synthDriver espeak
INFO - core.main (21:13:34.819):
Using wx version 3.0.2.0 msw (classic)
INFO - brailleInput.initialize (21:13:34.822):
Braille input initialized
INFO - braille.initialize (21:13:34.822):
Using liblouis version 3.3.0
INFO - braille.BrailleHandler.setDisplayByName (21:13:34.825):
Loaded braille display driver noBraille, current display has 0 cells.
WARNING - core.main (21:13:35.026):
Java Access Bridge not available
INFO - _UIAHandler.UIAHandler.MTAThreadFunc (21:13:35.045):
UIAutomation: IUIAutomation3
INFO - core.main (21:13:36.140):
NVDA initialized
ERROR - RPC process 14668 (nvda_slave.exe) (21:14:20.546):
main.main:
slave error
Traceback (most recent call last):
File "nvda_slave.pyw", line 42, in main
File "installer.pyc", line 414, in install
File "installer.pyc", line 159, in removeOldLibFiles
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe1 in position 17: ordinal not in range(128)
ERROR - gui.installerGui.doInstall (21:14:20.628):
Installation failed: 1

But then after rebooting from this temporary version of the new install the new version works fine as if it was installed successfully.

michaelDCurran added a commit that referenced this pull request Oct 20, 2017
@michaelDCurran

michaelDCurran commented Oct 20, 2017 via email

Copy link
Copy Markdown
Member Author

@Mary5958

Copy link
Copy Markdown
Contributor

Yes, it worked fine this time, thanks.

@michaelDCurran

Copy link
Copy Markdown
Member Author

@feerrenrut another review please. This time probably easiest to just review whole thing again as much of the code was removed and only left the most necessary bits, now isolated to the very end of the install. This now seems to work on all systems people have tested on, thankfully.

@Brian1Gaff

Brian1Gaff commented Oct 21, 2017 via email

Copy link
Copy Markdown

@michaelDCurran

michaelDCurran commented Oct 21, 2017 via email

Copy link
Copy Markdown
Member Author

@Brian1Gaff

Brian1Gaff commented Oct 21, 2017 via email

Copy link
Copy Markdown

@feerrenrut feerrenrut left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you outline what testing has been done on this? The permutations that I can think of are:

  • Different OS versions
  • Upgrade from installed 2017.3
  • Clean install
  • Upgrade of portable 2017.3

This is assuming that upgrade from last master or next is not so important.

Comment thread source/installer.py
else:
os.remove(fn)

# #7546: Remove old version-specific libs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this issue number still relevant? If so we should probably include it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue number was totally wrong. Not sure why it was there in the first place. It was pointing to the one about not supporting XP anymore.

Comment thread source/installer.py Outdated
tryCopyFile(os.path.join(destPath,"nvda_noUIAccess.exe"),os.path.join(destPath,"nvda.exe"))
if shouldCopyUserConfig:
copyUserConfig(os.path.join(destPath,'userConfig'))
removeOldLibFiles(destPath,rebootOK=False)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is rebootOK=False here, and rebootOK=True in def install?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because usually for portable copies it is impossible to delete after reboot as you need admin privilege to set this. However, there is no error if it doesn't work, so I've now allowed it anyway. Some people always running as admin this can work for. Plus, this also ensures that files remain renamed to temp files even if they can't be deleted on reboot, which keeps them out of the way of future installs.

@Brian1Gaff

Brian1Gaff commented Oct 23, 2017 via email

Copy link
Copy Markdown

…ser *may* have admin access which means it would work. Also it ensures the file, deleted or not, will still be kept renamed as a temp file out of the way.
@michaelDCurran

Copy link
Copy Markdown
Member Author

I have tested both on Windows 7 and Windows 10, for both installed and portable, for upgrading from 2017.3, and clean.

Comment thread source/installer.py
if shouldCopyUserConfig:
copyUserConfig(os.path.join(destPath,'userConfig'))
removeOldLibFiles(destPath,rebootOK=False)
removeOldLibFiles(destPath,rebootOK=True)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about the case where a portable copy resides on a removable drive and that drive is no longer available after a reboot? I assume Windows silently ignores this?

@michaelDCurran

michaelDCurran commented Oct 23, 2017 via email

Copy link
Copy Markdown
Member Author

@Brian1Gaff

Brian1Gaff commented Oct 23, 2017 via email

Copy link
Copy Markdown

@Brian1Gaff

Brian1Gaff commented Oct 23, 2017 via email

Copy link
Copy Markdown

michaelDCurran added a commit that referenced this pull request Oct 24, 2017
@michaelDCurran
michaelDCurran merged commit 1fcc7fe into master Oct 25, 2017
@nvaccessAuto nvaccessAuto added this to the 2017.4 milestone Oct 25, 2017
@Brian1Gaff

Brian1Gaff commented Oct 26, 2017 via email

Copy link
Copy Markdown

@Brian1Gaff

Brian1Gaff commented Nov 2, 2017 via email

Copy link
Copy Markdown

@Brian1Gaff

Brian1Gaff commented Nov 17, 2017 via email

Copy link
Copy Markdown

@michaelDCurran

michaelDCurran commented Nov 19, 2017 via email

Copy link
Copy Markdown
Member Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failures to update an installed copy of master branch Updating portable next snaps not working today

6 participants