|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Helper application for uninstalling a java application and |
|
15 * then installing new application (java or native) |
|
16 * |
|
17 */ |
|
18 |
|
19 #include <apgcli.h> |
|
20 #include <apacmdln.h> |
|
21 #include <apmstd.h> |
|
22 #include <bacline.h> |
|
23 #include <e32cmn.h> |
|
24 #include <s32mem.h> |
|
25 #include <unistd.h> |
|
26 |
|
27 #include "exceptionbase.h" |
|
28 #include "javaoslayer.h" |
|
29 #include "javaprocessconstants.h" |
|
30 #include "javasymbianoslayer.h" |
|
31 #include "javauids.h" |
|
32 #include "logger.h" |
|
33 |
|
34 |
|
35 using namespace java::util; |
|
36 |
|
37 |
|
38 _LIT(KHexValueStart, "0x"); |
|
39 _LIT(KSemiColon, ";"); |
|
40 _LIT(KUidArg, "uid="); |
|
41 _LIT(KFileArg, "file="); |
|
42 |
|
43 const TInt KExtraLenForLogging = 2; |
|
44 const TInt KArgumentValueMaxLen = 1568; |
|
45 // Wait for 0.5 sec if ArcApp has not yet initialized |
|
46 const TInt KDelayWhenWaitingAppArc = 500000; |
|
47 |
|
48 |
|
49 /** |
|
50 * Set the value of the argument specified by aArgName to aArgValue |
|
51 * |
|
52 * @param aCmdLine command line to be parsed |
|
53 * @param aArgName the name of the argument |
|
54 * @param aArgValue the value parsed from command line will be returned here |
|
55 */ |
|
56 static void getArgValueL(const TPtrC &aCmdLine, const TDesC &aArgName, HBufC **aArgValue) |
|
57 { |
|
58 TBuf<KArgumentValueMaxLen> valueBuf; |
|
59 TInt argPos = aCmdLine.FindF(aArgName); |
|
60 if (argPos >= 0) |
|
61 { |
|
62 TInt semicolonPos = aCmdLine.Mid(argPos).Find(KSemiColon); |
|
63 if (KErrNotFound == semicolonPos) |
|
64 { |
|
65 semicolonPos = aCmdLine.Mid(argPos).Length(); |
|
66 } |
|
67 TInt argLen = semicolonPos - aArgName.Length(); |
|
68 if (argLen >= KArgumentValueMaxLen) |
|
69 { |
|
70 // Protect from buffer overflow. |
|
71 WLOG2(EUtils, |
|
72 "javaupgradeapp: argument value len too long (%d), cutting it to %d", |
|
73 argLen, (KArgumentValueMaxLen - 1)); |
|
74 argLen = KArgumentValueMaxLen - 1; |
|
75 } |
|
76 else if (argLen == 0) |
|
77 { |
|
78 User::Leave(KErrArgument); |
|
79 } |
|
80 |
|
81 valueBuf = aCmdLine.Mid(argPos + aArgName.Length(), argLen); |
|
82 } |
|
83 |
|
84 // Allocate new HBufC and return it |
|
85 HBufC *pBufValue = HBufC::NewL(valueBuf.Length() + 2); |
|
86 *pBufValue = valueBuf; |
|
87 *aArgValue = pBufValue; |
|
88 } |
|
89 |
|
90 |
|
91 /** |
|
92 * Parse the name from the value of 'file' parameter in |
|
93 * command line given in aCmdLine |
|
94 * |
|
95 * @param aCmdLine command line to be parsed, the format is |
|
96 * <other_args>;file=YYY;<other_args> |
|
97 * @param aFileName will contain the name parsed from command line |
|
98 */ |
|
99 static void getNameFromCommandLineL(const TPtrC &aCmdLine, HBufC **aFileName) |
|
100 { |
|
101 TInt err = aCmdLine.FindF(KFileArg); |
|
102 User::LeaveIfError(err); |
|
103 |
|
104 getArgValueL(aCmdLine, KFileArg, aFileName); |
|
105 } |
|
106 |
|
107 |
|
108 /** |
|
109 * Parse the Uid from the value of 'uid' parameter in |
|
110 * command line given in aCmdLine |
|
111 * |
|
112 * @param aCmdLine command line to be parsed, the format is |
|
113 * uid=YYY;<other_args> |
|
114 * @param aUid will contain the Uid parsed from command line |
|
115 */ |
|
116 static void getUidFromCommandLineL(const TPtrC &aCmdLine, TInt32 &aUid) |
|
117 { |
|
118 TInt err(KErrNone); |
|
119 TInt argPos = aCmdLine.FindF(KUidArg); |
|
120 if (KErrNotFound != argPos) |
|
121 { |
|
122 TPtrC uidToParse = aCmdLine.Mid(argPos + KUidArg.iTypeLength); |
|
123 TLex parseUid(uidToParse); |
|
124 if (uidToParse.FindF(KHexValueStart) == 0) |
|
125 { |
|
126 parseUid.Inc(2); // skip hex prefix |
|
127 TUint32 tmpValue; |
|
128 err = parseUid.Val(tmpValue, EHex); |
|
129 aUid = tmpValue; |
|
130 } |
|
131 else |
|
132 { |
|
133 err = parseUid.Val(aUid); |
|
134 } |
|
135 |
|
136 if (KErrNone != err) |
|
137 { |
|
138 ELOG1(EUtils, |
|
139 "javaupgradeapp failed parsing app Uid from cmdline uid param. Error %d", |
|
140 err); |
|
141 } |
|
142 } |
|
143 else |
|
144 { |
|
145 ELOG(EUtils, |
|
146 "javaupgradeapp cannot uninstall app because uid parameter is not given"); |
|
147 } |
|
148 |
|
149 User::LeaveIfError(err); |
|
150 } |
|
151 |
|
152 |
|
153 /** |
|
154 * Parse the process command line. |
|
155 * Determine the uid of the Java application to be uninstalled and |
|
156 * the name of the application package to be installed. |
|
157 * Leaves if argument 'file' exist but file name cannot be found, |
|
158 * leaves if argument 'uid' exist but uid cannot be parsed from command line, |
|
159 * does NOT leave if only one of the arguments is present |
|
160 * |
|
161 * @param aFileName returns value of argument 'file' |
|
162 * @param aUid returns Uid of the Java application to be uninstalled |
|
163 */ |
|
164 void getFileAndUidL(HBufC **aFileName, TInt32 *aUid) |
|
165 { |
|
166 HBufC *pBufCmdLine = |
|
167 HBufC::NewLC(User::CommandLineLength() + KExtraLenForLogging); |
|
168 TPtr cmdLineBuf = pBufCmdLine->Des(); |
|
169 User::CommandLine(cmdLineBuf); |
|
170 |
|
171 if (cmdLineBuf.Length() > 0) |
|
172 { |
|
173 LOG1WSTR(EUtils, EInfo, |
|
174 "javaupgradeapp: full java application cmd line is : %s", |
|
175 (wchar_t *)(cmdLineBuf.PtrZ())); |
|
176 |
|
177 // Get the midlet uid from the commandline |
|
178 TRAPD(err, getUidFromCommandLineL(cmdLineBuf, *aUid)); |
|
179 // It is enough that either midlet uid OR installation package name |
|
180 // have been given in commandline |
|
181 if ((err != KErrNone) && (err != KErrNotFound)) |
|
182 { |
|
183 User::Leave(err); |
|
184 } |
|
185 |
|
186 // Get the name of the installation package from the commandline |
|
187 TRAPD(err2, getNameFromCommandLineL(cmdLineBuf, aFileName)) |
|
188 if (err2 != KErrNone) |
|
189 { |
|
190 if (err2 == KErrNotFound) |
|
191 { |
|
192 if (err == KErrNotFound) |
|
193 { |
|
194 // Both arguments missing |
|
195 User::Leave(KErrArgument); |
|
196 } |
|
197 } |
|
198 else |
|
199 { |
|
200 User::Leave(err2); |
|
201 } |
|
202 } |
|
203 } |
|
204 else |
|
205 { |
|
206 ELOG(EUtils, "javaupgradeapp: empty command line"); |
|
207 User::Leave(KErrArgument); |
|
208 } |
|
209 |
|
210 CleanupStack::PopAndDestroy(pBufCmdLine); |
|
211 } |
|
212 |
|
213 |
|
214 /** |
|
215 * Uninstall the java application specified by aUid parameter. |
|
216 * |
|
217 * @param aUid the Uid of the java application to be uninstalled |
|
218 */ |
|
219 void uninstallJavaAppL(TInt32 aUid) |
|
220 { |
|
221 RProcess rJavaInstaller; |
|
222 TFileName fileName; |
|
223 // Max one path name and some options -> 1536 is enough |
|
224 TBuf<1536> commandLine; |
|
225 |
|
226 // Build command line used to pass all necessary info to Java Installer |
|
227 TInt len = strlen(java::runtime::JAVA_INSTALLER_STARTER_DLL); |
|
228 TPtr8 ptr8InstallerDll((TUint8 *)java::runtime::JAVA_INSTALLER_STARTER_DLL, len, len); |
|
229 commandLine.Copy(ptr8InstallerDll); |
|
230 |
|
231 // Use command line options that make sure that uninstallation is done |
|
232 // always, silently and so that the uninstalled java application will |
|
233 // be preinstalled again if the user uninstalls it |
|
234 commandLine.Append(_L(" uninstall -uid=")); |
|
235 commandLine.AppendNum(aUid); |
|
236 commandLine.Append(_L(" -forceuninstall -silent -preinstall_always")); |
|
237 |
|
238 LOG1WSTR(EUtils, EInfo, |
|
239 "javaupgradeapp:uninstallJavaAppL Java Installer command line is %s", |
|
240 (wchar_t *)(commandLine.PtrZ())); |
|
241 |
|
242 // start JavaInstaller |
|
243 TBuf<64> installerProcess; // Actual len of the process name is 9 |
|
244 len = strlen(java::runtime::JAVA_PROCESS); |
|
245 TPtr8 ptr8Process((TUint8 *)java::runtime::JAVA_PROCESS, len, len); |
|
246 installerProcess.Copy(ptr8Process); |
|
247 |
|
248 TRequestStatus status; |
|
249 TInt err = rJavaInstaller.Create(installerProcess, commandLine); |
|
250 if (KErrNone == err) |
|
251 { |
|
252 LOG(EUtils, EInfo, "javaupgradeapp:uninstallJavaAppL calling Logon"); |
|
253 // Get notification when Java Installer exits (or panics) |
|
254 rJavaInstaller.Logon(status); |
|
255 |
|
256 LOG(EUtils, EInfo, "javaupgradeapp:uninstallJavaAppL calling Resume"); |
|
257 rJavaInstaller.Resume(); |
|
258 } |
|
259 else |
|
260 { |
|
261 ELOG1(EUtils, |
|
262 "javaupgradeapp:uninstallJavaAppL Cannot start Java Installer, error %d", |
|
263 err); |
|
264 User::Leave(err); |
|
265 } |
|
266 |
|
267 // now wait until Java Installer exits |
|
268 User::WaitForRequest(status); |
|
269 |
|
270 LOG(EUtils, EInfo, "javaupgradeapp:uninstallJavaAppL calling RProcess::Close"); |
|
271 // free resources before returning |
|
272 rJavaInstaller.Close(); |
|
273 } |
|
274 |
|
275 |
|
276 /** |
|
277 * |
|
278 * |
|
279 * |
|
280 */ |
|
281 void installAppPackageL(HBufC *aBufFileName) |
|
282 { |
|
283 // Open file using default handler, |
|
284 // if the file is an installation package, it will be installed |
|
285 RApaLsSession apaSession; |
|
286 TInt err = apaSession.Connect(); |
|
287 if (KErrNone != err) |
|
288 { |
|
289 ELOG(EUtils, |
|
290 "javaupgradeapp:installAppPackageL: Cannot connect to AppArc server"); |
|
291 User::Leave(err); |
|
292 } |
|
293 CleanupClosePushL(apaSession); |
|
294 |
|
295 TInt retryCounter(10); |
|
296 TThreadId handlerTreadId; |
|
297 do |
|
298 { |
|
299 err = apaSession.StartDocument(*aBufFileName, handlerTreadId); |
|
300 if (RApaLsSession::EAppListInvalid == err) |
|
301 { |
|
302 // Application list has not yet been populated, |
|
303 // try again after a short delay |
|
304 retryCounter--; |
|
305 if (retryCounter > 0) |
|
306 { |
|
307 User::After(KDelayWhenWaitingAppArc); |
|
308 continue; |
|
309 } |
|
310 else |
|
311 { |
|
312 ELOG(EUtils, |
|
313 "javaupgradeapp:installAppPackageL: RApaLsSession " |
|
314 "StartDocument returned EAppListInvalid for 10 times, exiting"); |
|
315 User::Leave(err); |
|
316 } |
|
317 } |
|
318 else if (KErrNone != err) |
|
319 { |
|
320 ELOG1(EUtils, |
|
321 "javaupgradeapp:installAppPackageL: RApaLsSession " |
|
322 "StartDocument returned error %d", err); |
|
323 User::Leave(err); |
|
324 } |
|
325 |
|
326 } while (RApaLsSession::EAppListInvalid == err); |
|
327 |
|
328 CleanupStack::PopAndDestroy(); // apaSession |
|
329 } |
|
330 |
|
331 |
|
332 /** |
|
333 * Get the uid of the Java application to be uninstaller and |
|
334 * start Java Installer to uninstall the application. |
|
335 * Then install the new application package given in cmdline |
|
336 * |
|
337 */ |
|
338 void handleUpgradeL(void) |
|
339 { |
|
340 HBufC *pBufFileName = NULL; |
|
341 TInt32 uid(0); |
|
342 |
|
343 getFileAndUidL(&pBufFileName, &uid); |
|
344 |
|
345 if (uid != 0) |
|
346 { |
|
347 LOG1( |
|
348 EUtils, |
|
349 EInfo, |
|
350 "javaupgradeapp uninstalling app uid %d", uid); |
|
351 uninstallJavaAppL(uid); |
|
352 } |
|
353 |
|
354 if (pBufFileName != NULL) |
|
355 { |
|
356 LOG1WSTR(EUtils, EInfo, |
|
357 "javaupgradeapp: installing new app package %s", |
|
358 (wchar_t *)(pBufFileName->Des().PtrZ())); |
|
359 installAppPackageL(pBufFileName); |
|
360 |
|
361 delete pBufFileName; |
|
362 } |
|
363 } |
|
364 |
|
365 |
|
366 /** |
|
367 * Main function of executable javaupgradeapp.exe. |
|
368 * "installer app" created by Services team starts this executable when |
|
369 * the "installer app" must be replaced with the real application (java/native or wrt) |
|
370 * |
|
371 * The command line format is |
|
372 * uid=<Uid>;file=<full_path_to_installation_file> |
|
373 * for example |
|
374 * uid=0x10137c4d;file=D:\\temp\\upgrade\\package.sis |
|
375 * |
|
376 * Sample code for starting this application from the "installer app" MIDlet |
|
377 * @code |
|
378 |
|
379 MIDlet.platformRequest( |
|
380 “nativeapp://application-exe=javaupgradeapp.exe;application-args=uid=0x10137c4d;file=D:\\temp\\upgrade\\package.sis”); |
|
381 |
|
382 * @endcode |
|
383 * |
|
384 */ |
|
385 TInt E32Main(void) |
|
386 { |
|
387 // TODO: check that only MIDP runtime process can start this in final version |
|
388 // that goes to ROM |
|
389 |
|
390 |
|
391 CTrapCleanup *pCleanupStack = CTrapCleanup::New(); |
|
392 if (NULL == pCleanupStack) |
|
393 { |
|
394 ELOG(EUtils, "Cannot create CleanupStack in javaupgradeapp.exe main()"); |
|
395 return KErrNoMemory; |
|
396 } |
|
397 |
|
398 TRAPD(err, handleUpgradeL()); |
|
399 if (KErrNone != err) |
|
400 { |
|
401 ELOG1(EUtils, "javaupgradeapp.exe: handleUpgradeL leaved with err %d", err); |
|
402 } |
|
403 |
|
404 delete pCleanupStack; |
|
405 return err; |
|
406 } |
|
407 |