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