|
1 /* |
|
2 * Copyright (c) 2006-2007 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: Logging to chunk wrappe for Mul |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // CLASS HEADER |
|
20 #include "mullogchunk.h" |
|
21 |
|
22 // EXTERNAL INCLUDES |
|
23 #include <e32svr.h> |
|
24 |
|
25 // LOCAL DECLARATIONS |
|
26 namespace |
|
27 { |
|
28 // size for the chunks |
|
29 const TInt KLogChunkSize = 1000000; // 1 million bytes |
|
30 // name for chunk 1 |
|
31 _LIT( KLogChunk1Name, "MUL_Logchunk1" ); |
|
32 // name for chunk 2 |
|
33 _LIT( KLogChunk2Name, "MUL_Logchunk2" ); |
|
34 // extension for log file |
|
35 _LIT( KLogFileExtension, ".log" ); |
|
36 // carriage return / line feed |
|
37 _LIT8( KLogCR, "\r" ); |
|
38 _LIT8( KLogLF, "\n" ); |
|
39 // constant for machine word alignment |
|
40 const TInt KBytesInAWord = sizeof( TInt32 ); |
|
41 } |
|
42 |
|
43 inline void Panic(TInt aReason) |
|
44 { |
|
45 _LIT(applicationName,"Mul Logging"); |
|
46 User::Panic(applicationName, aReason); |
|
47 } |
|
48 |
|
49 // ----------------------------------------------------------------------------- |
|
50 // RMulLogUtility::Open |
|
51 // ----------------------------------------------------------------------------- |
|
52 TInt RMulLogUtility::Open( const TDesC& aName, TBool aReadOnly ) |
|
53 { |
|
54 // open the chunk |
|
55 return iChunk.OpenGlobal( aName, aReadOnly ); |
|
56 } |
|
57 |
|
58 // ----------------------------------------------------------------------------- |
|
59 // RMulLogUtility::CreateL |
|
60 // ----------------------------------------------------------------------------- |
|
61 void RMulLogUtility::CreateL( const TDesC& aName ) |
|
62 { |
|
63 // create the chunk, leave if error |
|
64 TInt error = iChunk.CreateGlobal( aName, KLogChunkSize, KLogChunkSize ); |
|
65 // dont treate already exists as an error |
|
66 if( KErrAlreadyExists == error ) |
|
67 { |
|
68 // open in read-write |
|
69 User::LeaveIfError( iChunk.OpenGlobal( aName, EFalse ) ); |
|
70 } |
|
71 else |
|
72 { |
|
73 User::LeaveIfError( error ); |
|
74 } |
|
75 |
|
76 // initialise the iChunk to all zeros. |
|
77 Mem::FillZ( iChunk.Base(), iChunk.Size() ); |
|
78 // initialise current address to base |
|
79 SetCurrentAddress( BaseAddress() ); |
|
80 // initialise last logged address to base |
|
81 SetLastLoggedAddress( BaseAddress() ); |
|
82 } |
|
83 |
|
84 // ----------------------------------------------------------------------------- |
|
85 // RMulLogUtility::Close |
|
86 // ----------------------------------------------------------------------------- |
|
87 void RMulLogUtility::Close() |
|
88 { |
|
89 iChunk.Close(); |
|
90 } |
|
91 |
|
92 // ----------------------------------------------------------------------------- |
|
93 // RMulLogUtility::ChunkSize |
|
94 // ----------------------------------------------------------------------------- |
|
95 TInt RMulLogUtility::ChunkSize() |
|
96 { |
|
97 return iChunk.Size(); |
|
98 } |
|
99 |
|
100 // ----------------------------------------------------------------------------- |
|
101 // RMulLogUtility::Id |
|
102 // ----------------------------------------------------------------------------- |
|
103 TObjectId RMulLogUtility::Id() |
|
104 { |
|
105 // take chunk base address |
|
106 TUint8* ptr_in_chunk = iChunk.Base(); |
|
107 // cast that to TObjectId* |
|
108 TObjectId* ptr_as_tobjectid = reinterpret_cast< TObjectId* >( ptr_in_chunk ); |
|
109 // return the id |
|
110 return *ptr_as_tobjectid; |
|
111 } |
|
112 |
|
113 // ----------------------------------------------------------------------------- |
|
114 // RMulLogUtility::SetId |
|
115 // ----------------------------------------------------------------------------- |
|
116 void RMulLogUtility::SetId( TObjectId aId ) |
|
117 { |
|
118 // take chunk base address |
|
119 TUint8* ptr_in_chunk = iChunk.Base(); |
|
120 // cast that to TObjectId* |
|
121 TObjectId* ptr_as_tobjectid = reinterpret_cast< TObjectId* >( ptr_in_chunk ); |
|
122 // assign the id in place |
|
123 *ptr_as_tobjectid = aId; |
|
124 } |
|
125 |
|
126 // ----------------------------------------------------------------------------- |
|
127 // RMulLogUtility::CurrentAddress |
|
128 // ----------------------------------------------------------------------------- |
|
129 TUint8* RMulLogUtility::CurrentAddress() |
|
130 { |
|
131 // take chunk base address plus object id |
|
132 TUint8* ptr_in_chunk = iChunk.Base() + sizeof( TObjectId ); |
|
133 // cast that to TInt* |
|
134 TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk ); |
|
135 // dereference that pointer to read the 32 bits that are the address |
|
136 TUint32 value_of_pointer = *ptr_as_tint; |
|
137 // then return the value as TUint8* |
|
138 return reinterpret_cast< TUint8* >( value_of_pointer ); |
|
139 } |
|
140 |
|
141 // ----------------------------------------------------------------------------- |
|
142 // RMulLogUtility::SetCurrentAddress |
|
143 // ----------------------------------------------------------------------------- |
|
144 void RMulLogUtility::SetCurrentAddress( TUint8* aValue ) |
|
145 { |
|
146 // take chunk base address plus object id |
|
147 TUint8* ptr_in_chunk = iChunk.Base() + sizeof( TObjectId ); |
|
148 // cast that to TInt* |
|
149 TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk ); |
|
150 // assign the addres to TInt |
|
151 TUint32 new_value = reinterpret_cast< TUint32 >( aValue ); |
|
152 // ensure we're byte aligned - ARM requires 32 bit alignment to machine word |
|
153 // boundary!! |
|
154 TInt remainder = new_value % KBytesInAWord; |
|
155 if ( remainder > 0 ) |
|
156 { |
|
157 new_value += ( KBytesInAWord - remainder ); |
|
158 } |
|
159 // set the new value to the chunk |
|
160 *ptr_as_tint = new_value; |
|
161 } |
|
162 |
|
163 // ----------------------------------------------------------------------------- |
|
164 // RMulLogUtility::LastLoggedAddress |
|
165 // ----------------------------------------------------------------------------- |
|
166 TUint8* RMulLogUtility::LastLoggedAddress() |
|
167 { |
|
168 // take chunk base address plus object id plus one pointer |
|
169 TUint8* ptr_in_chunk = |
|
170 iChunk.Base() + sizeof( TObjectId ) + sizeof( TUint8* ); |
|
171 // cast that to TInt* |
|
172 TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk ); |
|
173 // dereference that pointer to read the 32 bits that are the address |
|
174 TUint32 value_of_pointer = *ptr_as_tint; |
|
175 // then return the value as TUint8* |
|
176 return reinterpret_cast< TUint8* >( value_of_pointer ); |
|
177 } |
|
178 |
|
179 // ----------------------------------------------------------------------------- |
|
180 // RMulLogUtility::SetLastLoggedAddress |
|
181 // ----------------------------------------------------------------------------- |
|
182 void RMulLogUtility::SetLastLoggedAddress( TUint8* aValue ) |
|
183 { |
|
184 // take chunk base address plus object id plus one pointer |
|
185 TUint8* ptr_in_chunk = |
|
186 iChunk.Base() + sizeof( TObjectId ) + sizeof( TUint8* ); |
|
187 // cast that to TInt* |
|
188 TUint32* ptr_as_tint = reinterpret_cast< TUint32* >( ptr_in_chunk ); |
|
189 // assign the addres to TInt |
|
190 TUint32 new_value = reinterpret_cast< TUint32 >( aValue ); |
|
191 // ensure we're byte aligned - ARM requires 32 bit alignment to machine word |
|
192 // boundary!! |
|
193 TInt remainder = new_value % KBytesInAWord; |
|
194 if ( remainder > 0 ) |
|
195 { |
|
196 new_value += ( KBytesInAWord - remainder ); |
|
197 } |
|
198 // set the new value to the chunk |
|
199 *ptr_as_tint = new_value; |
|
200 } |
|
201 |
|
202 // ----------------------------------------------------------------------------- |
|
203 // RMulLogUtility::BaseAddress |
|
204 // ----------------------------------------------------------------------------- |
|
205 TUint8* RMulLogUtility::BaseAddress() |
|
206 { |
|
207 // take chunks base address |
|
208 TUint8* base = iChunk.Base(); |
|
209 // calculate the topmost write address, our header is |
|
210 // TObjectId and two TUint8* |
|
211 return base + sizeof( TObjectId ) + sizeof( TUint8* ) * 2; |
|
212 } |
|
213 |
|
214 // ----------------------------------------------------------------------------- |
|
215 // RMulLogUtility::LastAddress |
|
216 // ----------------------------------------------------------------------------- |
|
217 TUint8* RMulLogUtility::LastAddress() |
|
218 { |
|
219 // return chunks base address plus its size |
|
220 return iChunk.Base() + iChunk.Size(); |
|
221 } |
|
222 |
|
223 // ----------------------------------------------------------------------------- |
|
224 // RMulLogClient::Open |
|
225 // ----------------------------------------------------------------------------- |
|
226 EXPORT_C TInt RMulLogClient::Open( TObjectId aId ) |
|
227 { |
|
228 // try to open first log chunk, in read-write mode |
|
229 TInt err = iLogUtility.Open( KLogChunk1Name(), EFalse ); |
|
230 if ( err != KErrNone ) |
|
231 { |
|
232 return err; |
|
233 } |
|
234 // check id |
|
235 TObjectId id = iLogUtility.Id(); |
|
236 if ( id == TObjectId( 0 ) ) |
|
237 { |
|
238 // no id set, so reserve this for us and use this chunk |
|
239 iLogUtility.SetId( aId ); |
|
240 } |
|
241 // check if our id was there? |
|
242 else if( id != aId ) |
|
243 { |
|
244 // not our chunk, try second chunk in read-write mode |
|
245 err = iLogUtility.Open( KLogChunk2Name(), EFalse ); |
|
246 if ( err != KErrNone ) |
|
247 { |
|
248 return err; |
|
249 } |
|
250 // check id |
|
251 id = iLogUtility.Id(); |
|
252 if ( id == TObjectId( 0 ) ) |
|
253 { |
|
254 // no id, reserve this for us and use this chunk |
|
255 iLogUtility.SetId( aId ); |
|
256 } |
|
257 else if ( id != aId ) |
|
258 { |
|
259 // both chunks already reserved, return error |
|
260 return KErrNotFound; |
|
261 } |
|
262 } |
|
263 return KErrNone; |
|
264 } |
|
265 |
|
266 // ----------------------------------------------------------------------------- |
|
267 // RMulLogClient::Close |
|
268 // ----------------------------------------------------------------------------- |
|
269 EXPORT_C void RMulLogClient::Close() |
|
270 { |
|
271 iLogUtility.Close(); |
|
272 } |
|
273 |
|
274 // ----------------------------------------------------------------------------- |
|
275 // RMulLogClient::Write |
|
276 // ----------------------------------------------------------------------------- |
|
277 EXPORT_C void RMulLogClient::Write( const TDesC8& aLogEntry ) |
|
278 { |
|
279 // get the size of log entry (in bytes) |
|
280 TInt num_bytes = aLogEntry.Size(); |
|
281 // take current address and chunk size to ensure log entry fits |
|
282 TUint8* current_address = iLogUtility.CurrentAddress(); |
|
283 // calculate the new current address, we write the size and the data |
|
284 TUint8* after_write = current_address + num_bytes + sizeof( TInt ); |
|
285 // chck that we fit |
|
286 if( after_write >= iLogUtility.LastAddress() ) |
|
287 { |
|
288 // we dont fit in the end |
|
289 // need to mark the old current_address so that |
|
290 // manager knows we jumped to the start |
|
291 TInt* last_indicator_ptr = |
|
292 reinterpret_cast< TInt* >( current_address ); |
|
293 // assign KErrNotFound there |
|
294 *last_indicator_ptr = KErrNotFound; |
|
295 // write this entry to the base address |
|
296 current_address = iLogUtility.BaseAddress(); |
|
297 } |
|
298 // we need to store the size in the chunk first so take a TInt* |
|
299 TInt* size_ptr = reinterpret_cast< TInt* >( current_address ); |
|
300 // assign new value in place |
|
301 *size_ptr = num_bytes; |
|
302 // increase address |
|
303 current_address += sizeof( TInt ); |
|
304 // copy the data, first target, then source and last number of bytes |
|
305 Mem::Copy( current_address, aLogEntry.Ptr(), num_bytes ); |
|
306 // and set the new current address |
|
307 iLogUtility.SetCurrentAddress( current_address + num_bytes ); |
|
308 } |
|
309 |
|
310 // ----------------------------------------------------------------------------- |
|
311 // RMulLogManager::CreateL |
|
312 // ----------------------------------------------------------------------------- |
|
313 EXPORT_C void RMulLogManager::CreateL() |
|
314 { |
|
315 // connect to the file server |
|
316 User::LeaveIfError( iFs.Connect() ); |
|
317 |
|
318 // create two log chunks |
|
319 iLogUtility1.CreateL( KLogChunk1Name ); |
|
320 iLogUtility2.CreateL( KLogChunk2Name ); |
|
321 } |
|
322 |
|
323 // ----------------------------------------------------------------------------- |
|
324 // RMulLogManager::Release |
|
325 // ----------------------------------------------------------------------------- |
|
326 EXPORT_C void RMulLogManager::Release() |
|
327 { |
|
328 // close file server handle |
|
329 iFs.Close(); |
|
330 |
|
331 // release both log chunks |
|
332 iLogUtility1.Close(); |
|
333 iLogUtility2.Close(); |
|
334 } |
|
335 |
|
336 // ----------------------------------------------------------------------------- |
|
337 // RMulLogManager::CommitToFileL |
|
338 // ----------------------------------------------------------------------------- |
|
339 EXPORT_C void RMulLogManager::CommitToFileL( const TDesC& aFolder ) |
|
340 { |
|
341 // open the file |
|
342 RFile file; |
|
343 CleanupClosePushL( file ); |
|
344 |
|
345 // chunk1 |
|
346 // create the file name |
|
347 TFileName fileName; |
|
348 fileName = aFolder; |
|
349 fileName.Append( KLogChunk1Name ); |
|
350 fileName.Append( KLogFileExtension ); |
|
351 // try to open the file |
|
352 TInt err = file.Open( iFs, fileName, EFileWrite ); |
|
353 if ( err == KErrNotFound ) |
|
354 { |
|
355 // file doesn't exist so create it |
|
356 err = file.Create( iFs, fileName, EFileWrite ); |
|
357 } |
|
358 User::LeaveIfError( err ); |
|
359 // write the first chunk to file |
|
360 CommitToFileL( iLogUtility1, file ); |
|
361 // close the file |
|
362 file.Close(); |
|
363 |
|
364 // chunk2 |
|
365 // reset the file name |
|
366 fileName.Zero(); |
|
367 // create the file name |
|
368 fileName = aFolder; |
|
369 fileName.Append( KLogChunk2Name ); |
|
370 fileName.Append( KLogFileExtension ); |
|
371 // try to open the file |
|
372 err = file.Open( iFs, fileName, EFileWrite ); |
|
373 if ( err == KErrNotFound ) |
|
374 { |
|
375 // file doesn't exist so create it |
|
376 err = file.Create( iFs, fileName, EFileWrite ); |
|
377 } |
|
378 User::LeaveIfError( err ); |
|
379 // write the second chunk to file |
|
380 CommitToFileL( iLogUtility2, file ); |
|
381 |
|
382 CleanupStack::PopAndDestroy( &file ); |
|
383 } |
|
384 |
|
385 // ----------------------------------------------------------------------------- |
|
386 // RMulLogManager::CommitToFileL |
|
387 // ----------------------------------------------------------------------------- |
|
388 void RMulLogManager::CommitToFileL( RMulLogUtility& aUtility, RFile& aFile ) |
|
389 { |
|
390 // Need to explicitly move to the end of the file as it's not done |
|
391 // automatically on call to Write |
|
392 TInt pos = 0; |
|
393 TInt err = aFile.Seek( ESeekEnd, pos ); |
|
394 User::LeaveIfError( err ); |
|
395 TPtr8 logEntryPtr( 0, 0 ); |
|
396 TInt logEntrySize = 0; |
|
397 |
|
398 // what's previously been logged to the file? |
|
399 TUint8* lastLoggedAddress = aUtility.LastLoggedAddress(); |
|
400 |
|
401 // how much more has been added to the chunk? |
|
402 TUint8* currentAddress = aUtility.CurrentAddress(); |
|
403 |
|
404 // write each of the chunk's logged entries to the file |
|
405 TInt32* sizePtr = NULL; |
|
406 while ( currentAddress != lastLoggedAddress && err == KErrNone ) |
|
407 { |
|
408 // get the logEntry's size |
|
409 sizePtr = reinterpret_cast< TInt32* >( lastLoggedAddress ); |
|
410 logEntrySize = *sizePtr; |
|
411 if ( logEntrySize == KErrNotFound ) |
|
412 { |
|
413 // logged entries have wrapped around the end of the chunk |
|
414 // so start from the beginning |
|
415 lastLoggedAddress = aUtility.BaseAddress(); |
|
416 sizePtr = reinterpret_cast< TInt32* >( lastLoggedAddress ); |
|
417 logEntrySize = *sizePtr; |
|
418 } |
|
419 // set an error - this will be reset to KErrNone if we succeed |
|
420 // with finding and writing a log entry |
|
421 err = KErrNotFound; |
|
422 if ( logEntrySize > 0 ) |
|
423 { |
|
424 // move the current address to the data |
|
425 lastLoggedAddress += sizeof( TInt32 ); |
|
426 // extract the log entry's data |
|
427 logEntryPtr.Set( lastLoggedAddress, logEntrySize, logEntrySize ); |
|
428 // write the log entry to the file |
|
429 err = aFile.Write( logEntryPtr ); |
|
430 // append carriage return and line feed to the entry |
|
431 err = aFile.Write( KLogCR ); |
|
432 err = aFile.Write( KLogLF ); |
|
433 // ensure we align to a multiple of a 4-byte boundary |
|
434 TInt remainder = logEntrySize % KBytesInAWord; |
|
435 if ( remainder > 0 ) |
|
436 { |
|
437 // not aligned so add some padding |
|
438 logEntrySize += ( KBytesInAWord - remainder ); |
|
439 } |
|
440 |
|
441 // update the last logged address |
|
442 lastLoggedAddress += logEntrySize; |
|
443 } |
|
444 } |
|
445 // update the last logged address |
|
446 aUtility.SetLastLoggedAddress( lastLoggedAddress ); |
|
447 // |
|
448 // commit the data |
|
449 err = aFile.Flush(); |
|
450 User::LeaveIfError( err ); |
|
451 } |