New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 632775 link

Starred by 3 users

Issue metadata

Status: Fixed
Owner:
Closed: Aug 2016
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: 2
Type: Bug



Sign in to add a comment

TaskManagerTableModel is inconsistent

Project Member Reported by a...@chromium.org, Jul 29 2016

Issue description

I'm porting NewTaskManagerViewTest.SelectionConsistency to the Mac and it's showing that the TaskManagerTableModel is inconsistent.

The key part is:
  // Add a new row in the same process as the selection. The selected tab should
  // not change.

At this point, row 6 is selected. The JavaScript opens a new process. At this point, the table model sends *3* ui::TableModelObserver calls:

1. OnItemsAdded(7, 1)
2. OnItemsRemoved(7, 1)
3. OnItemsAdded(7, 1)

After call 1, we have a new item. The Mac Task Manager calls GetRowsGroupRange on the table model, and gets the range (6-7), so it extends the selection through row 7. Now rows 6-7 are selected.

After call 2, the Mac Task Manager removes row 7, and now only row 6 is selected. The Mac Task Manager calls GetRowsGroupRange on the table model, and gets the range (6-7)!!!!! It extends the selection through row 7, which is an unrelated row. This is bad.

After call 3, the Mac Task Manager adds a new row 7, but the damage is done because we have a spurious row selection.

This needs to be fixed.
 

Comment 1 by a...@chromium.org, Jul 29 2016

More info:

Call 2 has the stack trace:

task_management::TaskManagerMac::OnItemsRemoved(int, int)
task_management::TaskManagerTableModel::OnTaskToBeRemoved(long long)
task_management::TaskManagerInterface::NotifyObserversOnTaskToBeRemoved(long long)
task_management::TaskManagerImpl::TaskRemoved(task_management::Task*)
task_management::TaskProvider::NotifyObserverTaskRemoved(task_management::Task*) const
task_management::WebContentsEntry::ClearAllTasks(bool)
task_management::WebContentsEntry::RenderViewReady()
content::WebContentsImpl::RenderViewReady(content::RenderViewHost*)

task_management::WebContentsEntry::RenderViewReady is:

  void RenderViewReady() override {
    ClearAllResources(true);
    CreateAllResources();
  }

Apparently that's not hooked up to grouping. Should it?

Comment 2 by a...@chromium.org, Jul 29 2016

It looks like it needs to be.

I added logging to the grouping code, and we get:

>> OnItemsAdded(7, 1)
] extending the selection of index 6 to start at 6 and be of length 2
] extending the selection of index 7 to start at 6 and be of length 2
>> OnItemsRemoved(7, 1)
] extending the selection of index 6 to start at 6 and be of length 2
] Yikes! The item at index 7 belongs to a group starting at 7 and of length 3! Ignoring.
>> OnItemsAdded(7, 1)
] extending the selection of index 6 to start at 6 and be of length 2
] extending the selection of index 7 to start at 6 and be of length 2

At that moment, the TaskManagerTableModel is serving data inconsistent with itself.

Comment 3 by a...@chromium.org, Jul 31 2016

The mismatch seems to be here:

void TaskManagerTableModel::OnTaskToBeRemoved(TaskId id) {
  auto index = std::find(tasks_.begin(), tasks_.end(), id);
  if (index == tasks_.end())
    return;
  auto removed_index = index - tasks_.begin();
  tasks_.erase(index);
  if (table_model_observer_)
    table_model_observer_->OnItemsRemoved(removed_index, 1);
}

The notification is that an item *will* be removed. The table model then removes it from its data, and tells the UI that the item *was* removed. The UI then asks the table model for grouping information, but TaskManagerTableModel::GetRowsGroupRange calls back to the task manager for its data, but the task manager is in the "pre-removal" state.

If the table model is going to transform "will be" removed to "was" removed, it has to translate the grouping as well.

Comment 4 by nick@chromium.org, Aug 1 2016

Awesome find. Thanks for digging into this.

Comment 5 by nick@chromium.org, Aug 1 2016

Status: Started (was: Assigned)

Comment 6 by nick@chromium.org, Aug 1 2016

Components: UI>TaskManager
If I understand correctly, there are are at least two bugs here:

 - The behavior of GetRowsGroupRange is inconsistent in the deletion case, since we've removed the item from TaskManagerTableModel::|tasks_| but the deleted item is still first in its group according to the TaskManager. I bet we can create a unittest for this case.

 - The RenderViewReady logic causes an unnecessary Remove/Add that exacerbates the first bug.

We should also inspect the code to see if there are other cases like GetRowsGroupRange.
Great find, Avi! Thanks!

Does switching the order fixes the issue? i.e.:

  if (table_model_observer_)
    table_model_observer_->OnItemsRemoved(removed_index, 1);
  tasks_.erase(index);

The wrong number of tasks per process in this task-removal transient state is probably what we want to avoid: https://cs.chromium.org/chromium/src/chrome/browser/ui/task_manager/task_manager_table_model.cc?q=TaskManagerTableModel::GetRowsGroupRange&sq=package:chromium&dr=C&l=574, correct?

Comment 8 by nick@chromium.org, Aug 1 2016

https://codereview.chromium.org/2202563003/ is what I was thinking.

Comment 9 by a...@chromium.org, Aug 1 2016

Re #7, that doesn't make much sense. The callback is "items were removed" so not actually removing it makes it worse.

I'm trying out Nick's patch to see if it works.

Comment 10 by a...@chromium.org, Aug 1 2016

Nick, Ahmed, can you look at https://codereview.chromium.org/2195873002/?

Comment 12 by a...@chromium.org, Aug 2 2016

Cc: nick@chromium.org
Owner: a...@chromium.org
Status: Fixed (was: Started)

Sign in to add a comment