|
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: A wrapper for the window group list, adding additional functionality required by OOM Monitor v2. |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <w32std.h> |
|
19 #include <e32std.h> |
|
20 #include <apgtask.h> |
|
21 #include <apgwgnam.h> |
|
22 |
|
23 #include "oomwindowgrouplist.h" |
|
24 #include "OomTraces.h" |
|
25 #include "oomconstants.hrh" |
|
26 #include "oompanic.h" |
|
27 |
|
28 #include "globaldata.h" |
|
29 #include "diclog.h" |
|
30 |
|
31 _LIT(KDummyWgName, "20"); |
|
32 const TInt KPreallocatedSpaceForAppList = 50; |
|
33 |
|
34 const TUint KOomTicksPerSecond = 1000; |
|
35 |
|
36 COomWindowGroupList::TOomWindowGroupProperties::TOomWindowGroupProperties() : iIdleTickTime(0), iDynamicPriority(EOomPriorityNormal) |
|
37 { |
|
38 FUNC_LOG; |
|
39 } |
|
40 |
|
41 // Update the list of window groups |
|
42 void COomWindowGroupList::Refresh() |
|
43 { |
|
44 TBuf<KIntValue9> buf(KWingoupListRefresh); |
|
45 DicLog::WriteLog(TUid::Uid(0x0003), buf); |
|
46 |
|
47 FUNC_LOG; |
|
48 |
|
49 #ifdef _DEBUG |
|
50 TRAPD(err, RefreshL()); |
|
51 if (err) |
|
52 { |
|
53 TRACES1("COomWindowGroupList::Refresh(): RefreshL leave %d", err); |
|
54 } |
|
55 #else |
|
56 TRAP_IGNORE(RefreshL()); |
|
57 // Ignore any error |
|
58 // Errors are very unlikely, the only possibility is OOM errors (which should be very unlikely due to pre-created, re-reserved lists) |
|
59 // The outcome of any error is that the most foreground operations will be missing from the list |
|
60 // meaning that they will not be considered candidates for closing |
|
61 #endif |
|
62 } |
|
63 |
|
64 // Update the list of window groups |
|
65 // Should be called whenever the |
|
66 void COomWindowGroupList::RefreshL() |
|
67 { |
|
68 FUNC_LOG; |
|
69 |
|
70 // Refresh window group list |
|
71 // get all window groups, with info about parents |
|
72 TInt numGroups = iWs.NumWindowGroups(0); |
|
73 iWgIds.ReserveL(numGroups); |
|
74 User::LeaveIfError(iWs.WindowGroupList(0, &iWgIds)); |
|
75 |
|
76 // Remove all child window groups, promote parents to foremost child position |
|
77 CollapseWindowGroupTree(); |
|
78 |
|
79 // Note the current foreground window ID (if there is one) |
|
80 TBool oldForegroundWindowExists = EFalse; |
|
81 |
|
82 TInt oldForegroundWindowId; |
|
83 if (iWgIds.Count() > 0) |
|
84 { |
|
85 oldForegroundWindowId = iWgIds[0].iId; |
|
86 oldForegroundWindowExists = ETrue; |
|
87 } |
|
88 |
|
89 // Cleanup the idletime hash map to remove idle times for any windows that have closed |
|
90 RemovePropertiesForClosedWindowsL(); |
|
91 |
|
92 // Update the idle tick on the old foreground application (which might now be in the background) |
|
93 // This will be set to the current system tick count and will be used later to determine the idle time |
|
94 if (oldForegroundWindowExists) |
|
95 { |
|
96 TOomWindowGroupProperties* wgProperties = iWgToPropertiesMapping.Find(oldForegroundWindowId); |
|
97 if (wgProperties) |
|
98 { |
|
99 wgProperties->iIdleTickTime = User::NTickCount(); |
|
100 } |
|
101 |
|
102 // If there is no idle tick entry for this window ID then it will be created in the next step... |
|
103 } |
|
104 |
|
105 TInt index = iWgIds.Count(); |
|
106 |
|
107 while (index--) |
|
108 { |
|
109 // See if there is a tick count entry for each window in the list |
|
110 TOomWindowGroupProperties* wgProperties = iWgToPropertiesMapping.Find(iWgIds[index].iId); |
|
111 |
|
112 if (!wgProperties) |
|
113 { |
|
114 TOomWindowGroupProperties wgProperties; |
|
115 wgProperties.iIdleTickTime = User::NTickCount(); |
|
116 // If there is no idle tick entry for this window then add one |
|
117 iWgToPropertiesMapping.InsertL(iWgIds[index].iId, wgProperties); |
|
118 } |
|
119 } |
|
120 } |
|
121 |
|
122 |
|
123 |
|
124 void COomWindowGroupList::RemovePropertiesForClosedWindowsL() |
|
125 { |
|
126 FUNC_LOG; |
|
127 |
|
128 // First, clear the existing set of window IDs (it would be quicker to delete it BUT we have reserved memory for it and don't want to be allocating in low memory conditions) |
|
129 RHashSet<TInt>::TIter windowIdSetIter(iExistingWindowIds); |
|
130 while (windowIdSetIter.Next()) |
|
131 { |
|
132 windowIdSetIter.RemoveCurrent(); |
|
133 } |
|
134 |
|
135 // Create the set of existing window IDs (this saves expensive/repeated searching later on) |
|
136 TInt index = iWgIds.Count(); |
|
137 while (index--) |
|
138 { |
|
139 iExistingWindowIds.InsertL(iWgIds[index].iId); |
|
140 } |
|
141 |
|
142 // Iterate the idle-time hash map - remove any items where the window no longer exists |
|
143 RHashMap<TInt, TOomWindowGroupProperties>::TIter wgToIdleIterator(iWgToPropertiesMapping); |
|
144 while (wgToIdleIterator.NextKey()) |
|
145 { |
|
146 // If the current key (window ID) does not exist in the set then remove the idle-time as it is no longer relevant |
|
147 if (!iExistingWindowIds.Find(*(wgToIdleIterator.CurrentKey()))) |
|
148 wgToIdleIterator.RemoveCurrent(); |
|
149 } |
|
150 } |
|
151 |
|
152 |
|
153 TUint COomWindowGroupList::AppId(TInt aIndex, TBool aResolveFromThread) const |
|
154 { |
|
155 FUNC_LOG; |
|
156 |
|
157 // get the app's details |
|
158 TPtr wgPtr(iWgNameBuf->Des()); |
|
159 |
|
160 TUid uid; |
|
161 |
|
162 TInt wgId = iWgIds[aIndex].iId; |
|
163 |
|
164 TInt err = iWs.GetWindowGroupNameFromIdentifier(wgId, wgPtr); |
|
165 |
|
166 if (KErrNone != err) |
|
167 // If there is an error then set the UID to 0; |
|
168 { |
|
169 uid.iUid = 0; |
|
170 } |
|
171 else |
|
172 { |
|
173 iWgName->SetWindowGroupName(iWgNameBuf); // iWgName takes ownership of iWgNameBuf |
|
174 uid = iWgName->AppUid(); // This UID comes from the app, not the mmp! |
|
175 if (aResolveFromThread && uid.iUid == 0) |
|
176 { |
|
177 TApaTask task(iWs); |
|
178 task.SetWgId(wgId); |
|
179 TThreadId threadId = task.ThreadId(); |
|
180 |
|
181 TUint resolvedUid = 0; |
|
182 RThread appThread; |
|
183 TInt err = appThread.Open( threadId ); |
|
184 if ( err == KErrNone ) |
|
185 { |
|
186 resolvedUid = appThread.SecureId().iId; |
|
187 } |
|
188 appThread.Close(); |
|
189 TRACES2("COomWindowGroupList::AppId: NULL wg UID, taking from thread; resolvedUid = %x aIndex = %d", resolvedUid, aIndex); |
|
190 return resolvedUid; |
|
191 } |
|
192 } |
|
193 |
|
194 return uid.iUid; |
|
195 } |
|
196 |
|
197 |
|
198 TTimeIntervalSeconds COomWindowGroupList::IdleTime(TInt aIndex) const |
|
199 { |
|
200 FUNC_LOG; |
|
201 |
|
202 TUint32 currentTickCount = User::NTickCount(); |
|
203 |
|
204 const TOomWindowGroupProperties* wgProperties = iWgToPropertiesMapping.Find(iWgIds[aIndex].iId); |
|
205 |
|
206 TTimeIntervalSeconds idleTime = 0; |
|
207 |
|
208 if (wgProperties) |
|
209 { |
|
210 // This should also handle the case where the current tick count has wrapped to a lower value than the idle tick time |
|
211 // It will only work if it has wrapped once, but |
|
212 TUint32 differenceBetweenTickCounts = currentTickCount - wgProperties->iIdleTickTime; |
|
213 idleTime = differenceBetweenTickCounts / KOomTicksPerSecond; |
|
214 } |
|
215 |
|
216 return idleTime; |
|
217 } |
|
218 |
|
219 |
|
220 |
|
221 void COomWindowGroupList::CollapseWindowGroupTree() |
|
222 { |
|
223 FUNC_LOG; |
|
224 |
|
225 // start from the front, wg count can reduce as loop runs |
|
226 for (TInt ii=0; ii<iWgIds.Count();) |
|
227 { |
|
228 RWsSession::TWindowGroupChainInfo& info = iWgIds[ii]; |
|
229 if (info.iParentId > 0) // wg has a parent |
|
230 { |
|
231 // Look for the parent position |
|
232 TInt parentPos = ii; // use child pos as not-found signal |
|
233 TInt count = iWgIds.Count(); |
|
234 for (TInt jj=0; jj<count; jj++) |
|
235 { |
|
236 if (iWgIds[jj].iId == info.iParentId) |
|
237 { |
|
238 parentPos = jj; |
|
239 break; |
|
240 } |
|
241 } |
|
242 |
|
243 if (parentPos > ii) // parent should be moved forward |
|
244 { |
|
245 iWgIds[ii] = iWgIds[parentPos]; |
|
246 iWgIds.Remove(parentPos); |
|
247 } |
|
248 else if (parentPos < ii) // parent is already ahead of child, remove child |
|
249 iWgIds.Remove(ii); |
|
250 else // parent not found, skip |
|
251 ii++; |
|
252 } |
|
253 else // wg does not have a parent, skip |
|
254 ii++; |
|
255 } |
|
256 } |
|
257 |
|
258 |
|
259 |
|
260 COomWindowGroupList::COomWindowGroupList(RWsSession& aWs) : iWs(aWs) |
|
261 { |
|
262 FUNC_LOG; |
|
263 } |
|
264 |
|
265 |
|
266 |
|
267 void COomWindowGroupList::ConstructL() |
|
268 { |
|
269 FUNC_LOG; |
|
270 |
|
271 // Reserve enough space to build an app list later. |
|
272 iWgIds.ReserveL(KPreallocatedSpaceForAppList); |
|
273 iUncollapsedWgIds.ReserveL(KPreallocatedSpaceForAppList); |
|
274 |
|
275 // Reserve enough space for the WG to idle tick mapping |
|
276 iWgToPropertiesMapping.ReserveL(KPreallocatedSpaceForAppList); |
|
277 |
|
278 // Reserve enough space for CApaWindowGroupName. |
|
279 iWgName = CApaWindowGroupName::NewL(iWs); |
|
280 iWgNameBuf = HBufC::NewL(CApaWindowGroupName::EMaxLength); |
|
281 (*iWgNameBuf) = KDummyWgName; |
|
282 iWgName->SetWindowGroupName(iWgNameBuf); // iWgName takes ownership of iWgNameBuf |
|
283 |
|
284 RefreshL(); |
|
285 } |
|
286 |
|
287 |
|
288 |
|
289 COomWindowGroupList* COomWindowGroupList::NewL(RWsSession& aWs) |
|
290 { |
|
291 FUNC_LOG; |
|
292 |
|
293 COomWindowGroupList* self = new (ELeave) COomWindowGroupList(aWs); |
|
294 CleanupStack::PushL(self); |
|
295 self->ConstructL(); |
|
296 CleanupStack::Pop(self); |
|
297 return self; |
|
298 } |
|
299 |
|
300 |
|
301 |
|
302 COomWindowGroupList::~COomWindowGroupList() |
|
303 { |
|
304 FUNC_LOG; |
|
305 |
|
306 iWgIds.Close(); |
|
307 iUncollapsedWgIds.Close(); |
|
308 iWgToPropertiesMapping.Close(); |
|
309 iExistingWindowIds.Close(); |
|
310 delete iWgName; |
|
311 } |
|
312 |
|
313 |
|
314 void COomWindowGroupList::SetPriorityBusy(TInt aWgId) |
|
315 { |
|
316 DicLog::WriteIntLog(TUid::Uid(0x0006),aWgId); |
|
317 |
|
318 FUNC_LOG; |
|
319 |
|
320 Refresh(); |
|
321 |
|
322 TInt parentId; |
|
323 TRAPD(err, parentId = FindParentIdL(aWgId)); |
|
324 if (err) |
|
325 { |
|
326 parentId = aWgId; |
|
327 } |
|
328 |
|
329 TOomWindowGroupProperties* wgProperties = iWgToPropertiesMapping.Find(parentId); |
|
330 if (wgProperties) |
|
331 { |
|
332 wgProperties->iDynamicPriority = EOomPriorityBusy; |
|
333 } |
|
334 |
|
335 // If we can't find the window group then ignore it |
|
336 } |
|
337 |
|
338 |
|
339 TInt COomWindowGroupList::FindParentIdL(TInt aWgId) |
|
340 { |
|
341 TInt numGroups = iWs.NumWindowGroups(0); |
|
342 iUncollapsedWgIds.ReserveL(numGroups); |
|
343 User::LeaveIfError(iWs.WindowGroupList(0, &iUncollapsedWgIds)); |
|
344 |
|
345 TInt parentPos = KErrNotFound; |
|
346 |
|
347 //loop through the window group list |
|
348 for (TInt i=0; i<numGroups; i++) |
|
349 { |
|
350 //find the index for the required aWgId |
|
351 if (iUncollapsedWgIds[i].iId == aWgId) |
|
352 { |
|
353 parentPos = i; |
|
354 break; |
|
355 } |
|
356 } |
|
357 |
|
358 if (parentPos >=0 ) |
|
359 { |
|
360 while (iUncollapsedWgIds[parentPos].iParentId > 0) |
|
361 { |
|
362 // find the index for the parent |
|
363 for (TInt j=0; j<numGroups; j++) |
|
364 { |
|
365 if (iUncollapsedWgIds[j].iId == iUncollapsedWgIds[parentPos].iParentId) |
|
366 { |
|
367 parentPos = j; |
|
368 break; // break out of inner loop |
|
369 } |
|
370 } |
|
371 } |
|
372 return iUncollapsedWgIds[parentPos].iId; |
|
373 } |
|
374 else |
|
375 { |
|
376 return KErrNotFound; |
|
377 } |
|
378 } |
|
379 |
|
380 |
|
381 TBool COomWindowGroupList::IsBusy(TInt aWgIndex) |
|
382 { |
|
383 TBool isBusy = EFalse; |
|
384 //__ASSERT_DEBUG(aWgIndex < iWgIds.Count(), OomMonitorPanic(KWindowGroupArrayIndexOutOfBounds)); |
|
385 TOomWindowGroupProperties* wgProperties = iWgToPropertiesMapping.Find(iWgIds[aWgIndex].iId); |
|
386 if (wgProperties) |
|
387 { |
|
388 isBusy = (wgProperties->iDynamicPriority == EOomPriorityBusy); |
|
389 } |
|
390 |
|
391 return isBusy; |
|
392 } |
|
393 |
|
394 // Returns ETrue if an application has registered itself as high priority at runtime |
|
395 TBool COomWindowGroupList::IsDynamicHighPriority(TInt aWgIndex) |
|
396 { |
|
397 FUNC_LOG; |
|
398 |
|
399 TBool isHighPriority = EFalse; |
|
400 //__ASSERT_DEBUG(aWgIndex < iWgIds.Count(), OomMonitorPanic(KWindowGroupArrayIndexOutOfBounds)); |
|
401 TOomWindowGroupProperties* wgProperties = iWgToPropertiesMapping.Find(iWgIds[aWgIndex].iId); |
|
402 if (wgProperties) |
|
403 { |
|
404 isHighPriority = (wgProperties->iDynamicPriority == EOomPriorityHigh); |
|
405 } |
|
406 |
|
407 return isHighPriority; |
|
408 } |
|
409 |
|
410 CApaWindowGroupName* COomWindowGroupList::WgName() const |
|
411 { |
|
412 return iWgName; |
|
413 } |
|
414 |
|
415 void COomWindowGroupList::SetPriorityNormal(TInt aWgId) |
|
416 { |
|
417 DicLog::WriteIntLog(TUid::Uid(0x0005),aWgId); |
|
418 |
|
419 FUNC_LOG; |
|
420 |
|
421 Refresh(); |
|
422 |
|
423 TInt parentId; |
|
424 TRAPD(err, parentId = FindParentIdL(aWgId)); |
|
425 if (err) |
|
426 { |
|
427 parentId = aWgId; |
|
428 } |
|
429 |
|
430 TOomWindowGroupProperties* wgProperties = iWgToPropertiesMapping.Find(parentId); |
|
431 if (wgProperties) |
|
432 { |
|
433 wgProperties->iDynamicPriority = EOomPriorityNormal; |
|
434 } |
|
435 |
|
436 // If we can't find the window group then ignore it |
|
437 } |
|
438 |
|
439 |
|
440 void COomWindowGroupList::SetPriorityHigh(TInt aWgId) |
|
441 { |
|
442 DicLog::WriteIntLog(TUid::Uid(0x0004),aWgId); |
|
443 |
|
444 FUNC_LOG; |
|
445 |
|
446 Refresh(); |
|
447 |
|
448 TInt parentId; |
|
449 TRAPD(err, parentId = FindParentIdL(aWgId)); |
|
450 if (err) |
|
451 { |
|
452 parentId = aWgId; |
|
453 } |
|
454 |
|
455 TOomWindowGroupProperties* wgProperties = iWgToPropertiesMapping.Find(parentId); |
|
456 if (wgProperties) |
|
457 { |
|
458 wgProperties->iDynamicPriority = EOomPriorityHigh; |
|
459 } |
|
460 |
|
461 // If we can't find the window group then ignore it |
|
462 } |
|
463 |
|
464 // Find the specificed application in the window group list and return the index |
|
465 TInt COomWindowGroupList::GetIndexFromAppId(TUint aAppId) const |
|
466 { |
|
467 FUNC_LOG; |
|
468 |
|
469 TInt indexInGroupList = Count(); |
|
470 TBool appFoundInWindowGroupList = EFalse; |
|
471 |
|
472 while (indexInGroupList--) |
|
473 { |
|
474 if (AppId(indexInGroupList, ETrue) == aAppId) |
|
475 { |
|
476 appFoundInWindowGroupList = ETrue; |
|
477 break; |
|
478 } |
|
479 } |
|
480 |
|
481 if (!appFoundInWindowGroupList) |
|
482 indexInGroupList = KAppNotInWindowGroupList; |
|
483 |
|
484 return indexInGroupList; |
|
485 } |