xref: /AOO41X/main/framework/qa/complex/framework/recovery/RecoveryTools.java (revision 47148b3bc50811ceb41802e4cc50a5db21535900)
1*76b6b121SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*76b6b121SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*76b6b121SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*76b6b121SAndrew Rist  * distributed with this work for additional information
6*76b6b121SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*76b6b121SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*76b6b121SAndrew Rist  * "License"); you may not use this file except in compliance
9*76b6b121SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*76b6b121SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*76b6b121SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*76b6b121SAndrew Rist  * software distributed under the License is distributed on an
15*76b6b121SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*76b6b121SAndrew Rist  * KIND, either express or implied.  See the License for the
17*76b6b121SAndrew Rist  * specific language governing permissions and limitations
18*76b6b121SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*76b6b121SAndrew Rist  *************************************************************/
21*76b6b121SAndrew Rist 
22*76b6b121SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir package complex.framework.recovery;
25cdf0e10cSrcweir 
26cdf0e10cSrcweir import com.sun.star.awt.XDialog;
27cdf0e10cSrcweir import com.sun.star.awt.XExtendedToolkit;
28cdf0e10cSrcweir import com.sun.star.awt.XWindow;
29cdf0e10cSrcweir import com.sun.star.beans.NamedValue;
30cdf0e10cSrcweir import com.sun.star.frame.XController;
31cdf0e10cSrcweir import com.sun.star.frame.XDesktop;
32cdf0e10cSrcweir import com.sun.star.frame.XDispatch;
33cdf0e10cSrcweir import com.sun.star.frame.XDispatchProvider;
34cdf0e10cSrcweir import com.sun.star.frame.XModel;
35cdf0e10cSrcweir import com.sun.star.lang.XComponent;
36cdf0e10cSrcweir import com.sun.star.lang.XMultiServiceFactory;
37cdf0e10cSrcweir import com.sun.star.ucb.XSimpleFileAccess;
38cdf0e10cSrcweir import com.sun.star.uno.UnoRuntime;
39cdf0e10cSrcweir import com.sun.star.uno.XInterface;
40cdf0e10cSrcweir import com.sun.star.util.URL;
41cdf0e10cSrcweir import com.sun.star.util.XURLTransformer;
42cdf0e10cSrcweir import helper.FileTools;
43cdf0e10cSrcweir import helper.OfficeProvider;
44cdf0e10cSrcweir import helper.UnoProvider;
45cdf0e10cSrcweir import java.io.File;
46cdf0e10cSrcweir import java.io.PrintWriter;
47cdf0e10cSrcweir import java.util.HashMap;
48cdf0e10cSrcweir import lib.TestParameters;
49cdf0e10cSrcweir import share.LogWriter;
50cdf0e10cSrcweir import util.PropertyName;
51cdf0e10cSrcweir import util.UITools;
52cdf0e10cSrcweir import util.utils;
53cdf0e10cSrcweir 
54cdf0e10cSrcweir /**
55cdf0e10cSrcweir  * this class supports the <CODE>RecoverTest</CODE>. You will find here some helper
56cdf0e10cSrcweir  * functions.
57cdf0e10cSrcweir  */
58cdf0e10cSrcweir public class RecoveryTools {
59cdf0e10cSrcweir 
60cdf0e10cSrcweir     private final TestParameters param;
61cdf0e10cSrcweir     private final LogWriter log;
62cdf0e10cSrcweir 
63cdf0e10cSrcweir     /**
64cdf0e10cSrcweir      * Creates new OfficeWatcher
65cdf0e10cSrcweir      * @param param the test parameter
66cdf0e10cSrcweir      * @param log a log writer
67cdf0e10cSrcweir      */
RecoveryTools(TestParameters param, LogWriter log)68cdf0e10cSrcweir     public RecoveryTools(TestParameters param, LogWriter log) {
69cdf0e10cSrcweir         this.param = param;
70cdf0e10cSrcweir         this.log = log;
71cdf0e10cSrcweir 
72cdf0e10cSrcweir     }
73cdf0e10cSrcweir 
74cdf0e10cSrcweir     /**
75cdf0e10cSrcweir      * get the active dialog from the top of the desktop
76cdf0e10cSrcweir      * @param xToolKit xToolKit the <CODE> XExtendedToolkit</CODE> to get the dialog from the top of the desktop.
77cdf0e10cSrcweir      * @return a <CODE>XDialog</CODE> interface of the dialog
78cdf0e10cSrcweir      */
getActiveDialog( XMultiServiceFactory xMSF)79cdf0e10cSrcweir     public XDialog getActiveDialog( XMultiServiceFactory xMSF){
80cdf0e10cSrcweir         XWindow xWin = getActiveWindow(xMSF);
81cdf0e10cSrcweir         return (XDialog) UnoRuntime.queryInterface(XDialog.class, xWin);
82cdf0e10cSrcweir     }
83cdf0e10cSrcweir 
getActiveWindow( XMultiServiceFactory xMSF)84cdf0e10cSrcweir     public XWindow getActiveWindow( XMultiServiceFactory xMSF){
85cdf0e10cSrcweir         XInterface xToolKit = null;
86cdf0e10cSrcweir         try {
87cdf0e10cSrcweir             xToolKit = (XInterface) xMSF.createInstance("com.sun.star.awt.Toolkit") ;
88cdf0e10cSrcweir         } catch (com.sun.star.uno.Exception e) {
89cdf0e10cSrcweir           return null;
90cdf0e10cSrcweir         }
91cdf0e10cSrcweir 
92cdf0e10cSrcweir         XExtendedToolkit tk = (XExtendedToolkit)
93cdf0e10cSrcweir             UnoRuntime.queryInterface(XExtendedToolkit.class, xToolKit);
94cdf0e10cSrcweir         Object atw = tk.getActiveTopWindow();
95cdf0e10cSrcweir         return (XWindow) UnoRuntime.queryInterface(XWindow.class, atw);
96cdf0e10cSrcweir     }
97cdf0e10cSrcweir 
98cdf0e10cSrcweir     /**
99cdf0e10cSrcweir      * After a crash the office start with a recovery diaolg. It could be that the office
100cdf0e10cSrcweir      * is connectable but not all services to get the dialog a loaded. This function
101cdf0e10cSrcweir      * tries to get the dialog until the <CODE>OfficeWatcher</CODE> kills the office.
102cdf0e10cSrcweir      * @param xToolKit the <CODE> XExtendedToolkit</CODE> to get the dialog from the top of the desktop.
103cdf0e10cSrcweir      * @return a <CODE>XDialog</CODE> interface of the dialog
104cdf0e10cSrcweir      */
getActiveDialogAfterStartup(XMultiServiceFactory xMSF)105cdf0e10cSrcweir     public XDialog getActiveDialogAfterStartup(XMultiServiceFactory xMSF){
106cdf0e10cSrcweir         // while the office starts it takes some time to get the dialog.
107cdf0e10cSrcweir 
108cdf0e10cSrcweir         // the dialog is accessible AFTER the office has recoverd all documents.
109cdf0e10cSrcweir         // This could consumes more time then the TimeOut allow.
110cdf0e10cSrcweir         int counter = 0;
111cdf0e10cSrcweir         int multi = 5;
112cdf0e10cSrcweir         int pause = param.getInt(PropertyName.SHORT_WAIT)*10;
113cdf0e10cSrcweir         int timeOut = param.getInt(PropertyName.THREAD_TIME_OUT)*5;
114cdf0e10cSrcweir         int maximum = (timeOut / pause) * multi;
115cdf0e10cSrcweir 
116cdf0e10cSrcweir         XDialog oDialog = getActiveDialog(xMSF);
117cdf0e10cSrcweir 
118cdf0e10cSrcweir         while (oDialog == null && (counter < maximum)){
119cdf0e10cSrcweir             log.println("waiting until the office has recoverd... remaining " + (timeOut * multi - pause * counter)/1000 + " seconds");
120cdf0e10cSrcweir             pause(pause);
121cdf0e10cSrcweir             oDialog = getActiveDialog(xMSF);
122cdf0e10cSrcweir             counter ++;
123cdf0e10cSrcweir         }
124cdf0e10cSrcweir         return oDialog;
125cdf0e10cSrcweir     }
126cdf0e10cSrcweir 
127cdf0e10cSrcweir     /**
128cdf0e10cSrcweir      * halt the thread for some time
129cdf0e10cSrcweir      */
pause()130cdf0e10cSrcweir     public void pause(){
131cdf0e10cSrcweir        pause(param.getInt(PropertyName.SHORT_WAIT));
132cdf0e10cSrcweir     }
133cdf0e10cSrcweir 
134cdf0e10cSrcweir     /**
135cdf0e10cSrcweir      * halt the thread for some time
136cdf0e10cSrcweir      */
pause(int sleepTime)137cdf0e10cSrcweir     public void pause(int sleepTime){
138cdf0e10cSrcweir         sleep(sleepTime);
139cdf0e10cSrcweir     }
140cdf0e10cSrcweir 
sleep(long millis)141cdf0e10cSrcweir     private void sleep(long millis){
142cdf0e10cSrcweir         try{
143cdf0e10cSrcweir             Thread.sleep(millis);
144cdf0e10cSrcweir         }catch (java.lang.InterruptedException e){}
145cdf0e10cSrcweir     }
146cdf0e10cSrcweir 
147cdf0e10cSrcweir     /**
148cdf0e10cSrcweir      * remove the content of the user backup folder and removes the Recovery.xcu. This
149cdf0e10cSrcweir      * was done from the Office via XSimpleFileAccess
150cdf0e10cSrcweir      * @throws com.sun.star.io.IOException the exception was thrown if something goes wrong.
151cdf0e10cSrcweir      */
cleanRecoveryData()152cdf0e10cSrcweir     public void cleanRecoveryData()
153cdf0e10cSrcweir         throws com.sun.star.io.IOException
154cdf0e10cSrcweir     {
155cdf0e10cSrcweir         try{
156cdf0e10cSrcweir             HashMap recFiles = getRecoveryFiles();
157cdf0e10cSrcweir 
158cdf0e10cSrcweir             String recoveryFolder = (String) recFiles.get("recoveryFolder");
159cdf0e10cSrcweir             String recoveryXCU = (String) recFiles.get("recoveryXCU");
160cdf0e10cSrcweir 
161cdf0e10cSrcweir             log.println("try to remove content of '" + recoveryFolder + "'");
162cdf0e10cSrcweir 
163cdf0e10cSrcweir             File rf = new File(recoveryFolder);
164cdf0e10cSrcweir 
165cdf0e10cSrcweir             boolean success = FileTools.cleanDir(rf);
166cdf0e10cSrcweir             log.println("removed " + recoveryFolder + ": " + success);
167cdf0e10cSrcweir 
168cdf0e10cSrcweir             log.println("try to remove '" + recoveryXCU + "'");
169cdf0e10cSrcweir 
170cdf0e10cSrcweir             File xcu = new File(recoveryXCU);
171cdf0e10cSrcweir             if (xcu.isFile()){
172cdf0e10cSrcweir                 success = xcu.delete();
173cdf0e10cSrcweir                 log.println("removed " + recoveryXCU + " : " + success);
174cdf0e10cSrcweir             }
175cdf0e10cSrcweir 
176cdf0e10cSrcweir         } catch (Exception e){
177cdf0e10cSrcweir             throw new com.sun.star.io.IOException("could not remove old recovery data: " + e.toString());
178cdf0e10cSrcweir         }
179cdf0e10cSrcweir     }
180cdf0e10cSrcweir 
getRecoveryFiles()181cdf0e10cSrcweir     public HashMap getRecoveryFiles()
182cdf0e10cSrcweir         throws com.sun.star.io.IOException
183cdf0e10cSrcweir     {
184cdf0e10cSrcweir         try{
185cdf0e10cSrcweir             log.println("try to get UnoProvider...");
186cdf0e10cSrcweir             UnoProvider unoProv = new UnoProvider();
187cdf0e10cSrcweir             XMultiServiceFactory xMSF = (XMultiServiceFactory) unoProv.getManager(param);
188cdf0e10cSrcweir 
189cdf0e10cSrcweir             String userPath = utils.expandMacro(xMSF, "${$ORIGIN/bootstraprc:UserInstallation}");
190cdf0e10cSrcweir             System.out.println("userPath:'" + userPath + "'");
191cdf0e10cSrcweir 
192cdf0e10cSrcweir             if (userPath.equals(""))userPath = utils.expandMacro(xMSF, "${$ORIGIN/bootstrap.ini:UserInstallation}");
193cdf0e10cSrcweir             System.out.println("userPath:'" + userPath + "'");
194cdf0e10cSrcweir 
195cdf0e10cSrcweir             if (userPath.equals("")) throw new com.sun.star.io.IOException("could not get user path at bootstraping");
196cdf0e10cSrcweir 
197cdf0e10cSrcweir             String recoveryFolder = utils.getSystemURL(userPath + "/user/backup");
198cdf0e10cSrcweir 
199cdf0e10cSrcweir             String recoveryXCU = utils.getSystemURL(userPath + "/user/registry/data/org/openoffice/Office/Recovery.xcu");
200cdf0e10cSrcweir 
201cdf0e10cSrcweir             HashMap recFiles = new HashMap();
202cdf0e10cSrcweir 
203cdf0e10cSrcweir             recFiles.put("recoveryFolder", recoveryFolder);
204cdf0e10cSrcweir             recFiles.put("recoveryXCU", recoveryXCU);
205cdf0e10cSrcweir             return recFiles;
206cdf0e10cSrcweir 
207cdf0e10cSrcweir         } catch (Exception e){
208cdf0e10cSrcweir             throw new com.sun.star.io.IOException("could not get recovery folder: " + e.toString());
209cdf0e10cSrcweir         }
210cdf0e10cSrcweir 
211cdf0e10cSrcweir     }
212cdf0e10cSrcweir     /**
213cdf0e10cSrcweir      * This function close the office while calling terminate on the desktop. If
214cdf0e10cSrcweir      * this failed, the <CODE>ProcessHandler</CODE> kills the process.
215cdf0e10cSrcweir      * @param xMSF the <CODE>XMultiServiceFactory</CODE>
216cdf0e10cSrcweir      * @return <CODE>TRUE</CODE> if no exception was thrown, otherwise <CODE>FALSE</CODE>
217cdf0e10cSrcweir      */
closeOffice(XMultiServiceFactory xMSF)218cdf0e10cSrcweir     public boolean closeOffice(XMultiServiceFactory xMSF) {
219cdf0e10cSrcweir         try {
220cdf0e10cSrcweir             XDesktop desk = (XDesktop) UnoRuntime.queryInterface(
221cdf0e10cSrcweir                     XDesktop.class, xMSF.createInstance(
222cdf0e10cSrcweir                     "com.sun.star.frame.Desktop"));
223cdf0e10cSrcweir             xMSF = null;
224cdf0e10cSrcweir 
225cdf0e10cSrcweir             desk.terminate();
226cdf0e10cSrcweir             log.println("Waiting until ProcessHandler loose the office...");
227cdf0e10cSrcweir 
228cdf0e10cSrcweir         }
229cdf0e10cSrcweir         catch (java.lang.Exception e) {
230cdf0e10cSrcweir             e.printStackTrace();
231cdf0e10cSrcweir             return false;
232cdf0e10cSrcweir         }
233cdf0e10cSrcweir         waitForClosedOffice();
234cdf0e10cSrcweir         return true;
235cdf0e10cSrcweir     }
236cdf0e10cSrcweir 
237cdf0e10cSrcweir     /**
238cdf0e10cSrcweir      * This function waits until the office is closed. If the closing time reach
239cdf0e10cSrcweir      * the value of parameter <CODE>THREAD_TIME_OUT</CODE> the office was killed.
240cdf0e10cSrcweir      */
waitForClosedOffice()241cdf0e10cSrcweir     public void waitForClosedOffice(){
242cdf0e10cSrcweir         // check for the office process
243cdf0e10cSrcweir         helper.ProcessHandler ph = (helper.ProcessHandler) param.get("AppProvider");
244cdf0e10cSrcweir 
245cdf0e10cSrcweir         int timeOut = param.getInt(PropertyName.THREAD_TIME_OUT)*5;
246cdf0e10cSrcweir         int pause = param.getInt(PropertyName.SHORT_WAIT)*20;
247cdf0e10cSrcweir         int multi = 0;
248cdf0e10cSrcweir         while ((ph != null) && (ph.getExitCode()<0) && (pause*multi < timeOut)) {
249cdf0e10cSrcweir             log.println("waiting until the office is closed... remaining " + (timeOut - pause * multi)/1000 + " seconds");
250cdf0e10cSrcweir             pause(pause);
251cdf0e10cSrcweir             multi ++;
252cdf0e10cSrcweir         }
253cdf0e10cSrcweir 
254cdf0e10cSrcweir         // be shure that office is closed
255cdf0e10cSrcweir         if (ph != null) ph.kill();
256cdf0e10cSrcweir     }
257cdf0e10cSrcweir 
killOffice()258cdf0e10cSrcweir     public void killOffice(){
259cdf0e10cSrcweir         helper.ProcessHandler ph = (helper.ProcessHandler) param.get("AppProvider");
260cdf0e10cSrcweir         ph.kill();
261cdf0e10cSrcweir     }
262cdf0e10cSrcweir 
263cdf0e10cSrcweir     /**
264cdf0e10cSrcweir      * The office must be started WITH restore and crashreporter functionality.
265cdf0e10cSrcweir      * Therefore the parmater '<CODE>-norestore</CODE>' and '<CODE>-nocrashreport</CODE>'
266cdf0e10cSrcweir      * was removed from the <CODE>AppExecutionCommand</CODE> parameter
267cdf0e10cSrcweir      */
removeParametersFromAppExecutionCommand()268cdf0e10cSrcweir     public void removeParametersFromAppExecutionCommand(){
269cdf0e10cSrcweir 
270cdf0e10cSrcweir         //remove some params to start office
271cdf0e10cSrcweir         String office = (String) param.get("AppExecutionCommand");
272cdf0e10cSrcweir         String[] params = {"-norestore", "-nocrashreport"};
273cdf0e10cSrcweir 
274cdf0e10cSrcweir         for (int i = 0; i < params.length; i++){
275cdf0e10cSrcweir             int index = office.indexOf(params[i]);
276cdf0e10cSrcweir             int length = params[i].length();
277cdf0e10cSrcweir             if (index != -1){
278cdf0e10cSrcweir                 office = office.substring(0, index) + office.substring(index + length);
279cdf0e10cSrcweir                 log.println("removed '" + params[i] + "' from AppExecutionCommand: " + office);
280cdf0e10cSrcweir             }
281cdf0e10cSrcweir         }
282cdf0e10cSrcweir         param.put("AppExecutionCommand", office);
283cdf0e10cSrcweir         log.println("connect: " + (String) param.get("AppExecutionCommand"));
284cdf0e10cSrcweir 
285cdf0e10cSrcweir     }
286cdf0e10cSrcweir 
287cdf0e10cSrcweir     /**
288cdf0e10cSrcweir      * This function uses accessibility to handle modal dialogs like the
289cdf0e10cSrcweir      * "Are you sure" dialog.
290cdf0e10cSrcweir      * It cklick the named button given in parameter <CODE>buttonName</CODE>
291cdf0e10cSrcweir      * @param buttonName the name of the button wich should be chlicked
292cdf0e10cSrcweir      */
handleModalDialog(XMultiServiceFactory xMSF, String buttonName)293cdf0e10cSrcweir     public void handleModalDialog(XMultiServiceFactory xMSF, String buttonName)
294cdf0e10cSrcweir                 throws com.sun.star.accessibility.IllegalAccessibleComponentStateException
295cdf0e10cSrcweir     {
296cdf0e10cSrcweir 
297cdf0e10cSrcweir         log.println("try to get modal Dialog...");
298cdf0e10cSrcweir 
299cdf0e10cSrcweir         pause();
300cdf0e10cSrcweir 
301cdf0e10cSrcweir         XWindow oDialog = getActiveWindow(xMSF);
302cdf0e10cSrcweir 
303cdf0e10cSrcweir         if (oDialog == null) throw new com.sun.star.accessibility.IllegalAccessibleComponentStateException("could not get modal Dialog");
304cdf0e10cSrcweir 
305cdf0e10cSrcweir 
306cdf0e10cSrcweir         UITools oUITools = new UITools(xMSF, oDialog);
307cdf0e10cSrcweir         oUITools.printAccessibleTree((PrintWriter) log, param.getBool(PropertyName.DEBUG_IS_ACTIVE));
308cdf0e10cSrcweir 
309cdf0e10cSrcweir         try{
310cdf0e10cSrcweir             log.println("click ' " + buttonName + "' button..");
311cdf0e10cSrcweir             oUITools.clickButton(buttonName);
312cdf0e10cSrcweir         } catch ( java.lang.Exception e){
313cdf0e10cSrcweir             throw new com.sun.star.accessibility.IllegalAccessibleComponentStateException("Could not klick '"+buttonName +"' at modal dialog: " + e.toString());
314cdf0e10cSrcweir         }
315cdf0e10cSrcweir         pause();
316cdf0e10cSrcweir     }
317cdf0e10cSrcweir 
clickThreadButton(XMultiServiceFactory xMSF, XWindow xWindow, String buttonName)318cdf0e10cSrcweir     public void clickThreadButton(XMultiServiceFactory xMSF, XWindow xWindow, String buttonName)
319cdf0e10cSrcweir                 throws com.sun.star.accessibility.IllegalAccessibleComponentStateException
320cdf0e10cSrcweir     {
321cdf0e10cSrcweir         KlickButtonThread kbt = new KlickButtonThread(xMSF, xWindow, buttonName);
322cdf0e10cSrcweir         kbt.start();
323cdf0e10cSrcweir         pause(param.getInt(PropertyName.SHORT_WAIT) * 10);
324cdf0e10cSrcweir     }
325cdf0e10cSrcweir 
copyRecoveryData(boolean backup)326cdf0e10cSrcweir     public void copyRecoveryData(boolean backup)
327cdf0e10cSrcweir         throws com.sun.star.io.IOException, java.io.IOException
328cdf0e10cSrcweir     {
329cdf0e10cSrcweir         HashMap recFiles = null;
330cdf0e10cSrcweir 
331cdf0e10cSrcweir         try{
332cdf0e10cSrcweir             recFiles = getRecoveryFiles();
333cdf0e10cSrcweir         } catch ( com.sun.star.io.IOException e){
334cdf0e10cSrcweir             throw new  com.sun.star.io.IOException("Could not get recovery files: " + e.toString());
335cdf0e10cSrcweir         }
336cdf0e10cSrcweir 
337cdf0e10cSrcweir         try{
338cdf0e10cSrcweir             String recoveryFolder = (String) recFiles.get("recoveryFolder");
339cdf0e10cSrcweir             String recoveryXCU = (String) recFiles.get("recoveryXCU");
340cdf0e10cSrcweir 
341cdf0e10cSrcweir             File recFolder = new File(recoveryFolder);
342cdf0e10cSrcweir             File recFolderBackup = new File(recoveryFolder+".recoveryTest");
343cdf0e10cSrcweir 
344cdf0e10cSrcweir             File recXCU = new File(recoveryXCU);
345cdf0e10cSrcweir             File recXCUBackup = new File(recoveryXCU + ".recoveryTest");
346cdf0e10cSrcweir 
347cdf0e10cSrcweir             if (backup){
348cdf0e10cSrcweir                 FileTools.copyDirectory(recFolder, recFolderBackup);
349cdf0e10cSrcweir                 FileTools.copyFile(recXCU, recXCUBackup);
350cdf0e10cSrcweir             } else {
351cdf0e10cSrcweir                 FileTools.copyDirectory(recFolderBackup, recFolder);
352cdf0e10cSrcweir                 FileTools.copyFile(recXCUBackup, recXCU);
353cdf0e10cSrcweir 
354cdf0e10cSrcweir             }
355cdf0e10cSrcweir         } catch (java.io.IOException e){
356cdf0e10cSrcweir             throw new java.io.IOException("Could not copy recovery files: " + e.toString());
357cdf0e10cSrcweir         }
358cdf0e10cSrcweir    }
359cdf0e10cSrcweir 
360cdf0e10cSrcweir 
361cdf0e10cSrcweir }
362