blob: 5309243220d1f2529ca9b9b727694780e9200862 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.deployer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class ApkMap {
public static class Area {
public Area(long start, long end) {
this.start = start;
this.end = end;
}
// Both offset are inclusive. The area start=1, end=2 has a size of two
// where both offset 1 and offset 2 are included in the area.
final long start;
final long end;
long size() {
return end - start + 1;
}
}
// ApkMap helps to build a map of the dirty Areas (dirty = has changed)
// of a binary file, using only the known clean Areas.
// The initial state is to mark everything as dirty: [DDDDDDDDDDDDDDDDDD]
// Calls to markClean() fraction the map into areas: [ CCC ]
// [ C ]
// [C ]
// At the end of the process, getDirtyAreas returns [ ]
// a set of areas describing what is not clean : [ DDD DDDDDDDDD D]
private List<Area> cleanAreas = new ArrayList<>();
private final long size;
public ApkMap(long size) {
this.size = size;
}
// It is expected that this new cleanArea does NOT overlap with any of the previously
// declared clean areas. If not, the final dirty map will feature false negatives
// (clear area will still be marked as dirty).
public void markClean(Area cleanArea) {
cleanAreas.add(cleanArea);
}
public List<Area> getDirtyAreas() {
// Add markers at the beginning and the end so this algorithm is more straightforward.
cleanAreas.add(new Area(-1, -1));
cleanAreas.add(new Area(size, size));
// Sort clear areas so they are in ascending order
cleanAreas.sort((Area o1, Area o2) -> Long.compare(o1.start, o2.start));
// Build a dirty map from a sorted list of clean non-overlapping areas.
LinkedList<Area> dirtyAreas = new LinkedList<>();
Iterator<Area> iterator = cleanAreas.iterator();
Area previous = iterator.next();
while (iterator.hasNext()) {
Area current = iterator.next();
Area dirtyArea = new Area(previous.end + 1, current.start - 1);
if (dirtyArea.size() > 0) {
dirtyAreas.add(dirtyArea);
}
previous = current;
}
return dirtyAreas;
}
}