summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/art_method-inl.h1
-rw-r--r--runtime/gc/collector/concurrent_copying.cc77
-rw-r--r--tools/ahat/etc/ahat_api.txt2
-rw-r--r--tools/ahat/src/main/com/android/ahat/ObjectsHandler.java102
-rw-r--r--tools/ahat/src/main/com/android/ahat/Query.java16
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java15
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java19
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Site.java27
-rw-r--r--tools/ahat/src/test/com/android/ahat/AhatTestSuite.java1
-rw-r--r--tools/ahat/src/test/com/android/ahat/ObjectsHandlerTest.java55
-rw-r--r--tools/ahat/src/test/com/android/ahat/QueryTest.java3
-rw-r--r--tools/veridex/hidden_api_finder.cc6
12 files changed, 262 insertions, 62 deletions
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index f693524a6c..9b69166567 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -417,7 +417,6 @@ inline HiddenApiAccessFlags::ApiList ArtMethod::GetHiddenApiAccessFlags()
case Intrinsics::kMemoryPokeIntNative:
case Intrinsics::kMemoryPokeLongNative:
case Intrinsics::kMemoryPokeShortNative:
- return HiddenApiAccessFlags::kDarkGreylist;
case Intrinsics::kVarHandleFullFence:
case Intrinsics::kVarHandleAcquireFence:
case Intrinsics::kVarHandleReleaseFence:
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 3a800088ba..0c187675ba 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -2331,6 +2331,7 @@ void ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace(mirror::Object* o
CHECK(!region_space_->HasAddress(ref)) << "obj=" << obj << " ref=" << ref;
// In a non-moving space. Check that the ref is marked.
if (immune_spaces_.ContainsObject(ref)) {
+ // Immune space case.
if (kUseBakerReadBarrier) {
// Immune object may not be gray if called from the GC.
if (Thread::Current() == thread_running_gc_ && !gc_grays_immune_objects_) {
@@ -2344,28 +2345,68 @@ void ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace(mirror::Object* o
<< " updated_all_immune_objects=" << updated_all_immune_objects;
}
} else {
+ // Non-moving space and large-object space (LOS) cases.
accounting::ContinuousSpaceBitmap* mark_bitmap =
heap_mark_bitmap_->GetContinuousSpaceBitmap(ref);
accounting::LargeObjectBitmap* los_bitmap =
heap_mark_bitmap_->GetLargeObjectBitmap(ref);
- bool is_los = mark_bitmap == nullptr;
- if ((!is_los && mark_bitmap->Test(ref)) ||
- (is_los && los_bitmap->Test(ref))) {
- // OK.
- } else {
- // If `ref` is on the allocation stack, then it may not be
- // marked live, but considered marked/alive (but not
- // necessarily on the live stack).
- CHECK(IsOnAllocStack(ref))
- << "Unmarked ref that's not on the allocation stack."
- << " obj=" << obj
- << " ref=" << ref
- << " rb_state=" << ref->GetReadBarrierState()
- << " is_los=" << std::boolalpha << is_los << std::noboolalpha
- << " is_marking=" << std::boolalpha << is_marking_ << std::noboolalpha
- << " young_gen=" << std::boolalpha << young_gen_ << std::noboolalpha
- << " self=" << Thread::Current();
- }
+ bool is_los = (mark_bitmap == nullptr);
+
+ bool marked_in_non_moving_space_or_los =
+ (kUseBakerReadBarrier
+ && kEnableGenerationalConcurrentCopyingCollection
+ && young_gen_
+ && !done_scanning_.load(std::memory_order_acquire))
+ // Don't use the mark bitmap to ensure `ref` is marked: check that the
+ // read barrier state is gray instead. This is to take into account a
+ // potential race between two read barriers on the same reference when the
+ // young-generation collector is still scanning the dirty cards.
+ //
+ // For instance consider two concurrent read barriers on the same GC root
+ // reference during the dirty-card-scanning step of a young-generation
+ // collection. Both threads would call ReadBarrier::BarrierForRoot, which
+ // would:
+ // a. mark the reference (leading to a call to
+ // ConcurrentCopying::MarkNonMoving); then
+ // b. check the to-space invariant (leading to a call this
+ // ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace -- this
+ // method).
+ //
+ // In this situation, the following race could happen:
+ // 1. Thread A successfully changes `ref`'s read barrier state from
+ // non-gray (white) to gray (with AtomicSetReadBarrierState) in
+ // ConcurrentCopying::MarkNonMoving, then gets preempted.
+ // 2. Thread B also tries to change `ref`'s read barrier state with
+ // AtomicSetReadBarrierState from non-gray to gray in
+ // ConcurrentCopying::MarkNonMoving, but fails, as Thread A already
+ // changed it.
+ // 3. Because Thread B failed the previous CAS, it does *not* set the
+ // bit in the mark bitmap for `ref`.
+ // 4. Thread B checks the to-space invariant and calls
+ // ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace: the bit
+ // is not set in the mark bitmap for `ref`; checking that this bit is
+ // set to check the to-space invariant is therefore not a reliable
+ // test.
+ // 5. (Note that eventually, Thread A will resume its execution and set
+ // the bit for `ref` in the mark bitmap.)
+ ? (ref->GetReadBarrierState() == ReadBarrier::GrayState())
+ // It is safe to use the heap mark bitmap otherwise.
+ : (!is_los && mark_bitmap->Test(ref)) || (is_los && los_bitmap->Test(ref));
+
+ // If `ref` is on the allocation stack, then it may not be
+ // marked live, but considered marked/alive (but not
+ // necessarily on the live stack).
+ CHECK(marked_in_non_moving_space_or_los || IsOnAllocStack(ref))
+ << "Unmarked ref that's not on the allocation stack."
+ << " obj=" << obj
+ << " ref=" << ref
+ << " rb_state=" << ref->GetReadBarrierState()
+ << " is_los=" << std::boolalpha << is_los << std::noboolalpha
+ << " is_marking=" << std::boolalpha << is_marking_ << std::noboolalpha
+ << " young_gen=" << std::boolalpha << young_gen_ << std::noboolalpha
+ << " done_scanning="
+ << std::boolalpha << done_scanning_.load(std::memory_order_acquire) << std::noboolalpha
+ << " self=" << Thread::Current();
}
}
diff --git a/tools/ahat/etc/ahat_api.txt b/tools/ahat/etc/ahat_api.txt
index 5426f7b866..7aa994a805 100644
--- a/tools/ahat/etc/ahat_api.txt
+++ b/tools/ahat/etc/ahat_api.txt
@@ -96,6 +96,7 @@ package com.android.ahat.heapdump {
method public boolean isArrayInstance();
method public boolean isClassInstance();
method public boolean isClassObj();
+ method public boolean isInstanceOfClass(java.lang.String);
method public boolean isPlaceHolder();
method public boolean isRoot();
method public boolean isStronglyReachable();
@@ -226,6 +227,7 @@ package com.android.ahat.heapdump {
method public int getLineNumber();
method public java.lang.String getMethodName();
method public void getObjects(java.lang.String, java.lang.String, java.util.Collection<com.android.ahat.heapdump.AhatInstance>);
+ method public void getObjects(java.util.function.Predicate<com.android.ahat.heapdump.AhatInstance>, java.util.function.Consumer<com.android.ahat.heapdump.AhatInstance>);
method public java.util.List<com.android.ahat.heapdump.Site.ObjectsInfo> getObjectsInfos();
method public com.android.ahat.heapdump.Site getParent();
method public java.lang.String getSignature();
diff --git a/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java b/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java
index 1a8f018bd5..81611b6c72 100644
--- a/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java
+++ b/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java
@@ -16,6 +16,7 @@
package com.android.ahat;
+import com.android.ahat.heapdump.AhatHeap;
import com.android.ahat.heapdump.AhatInstance;
import com.android.ahat.heapdump.AhatSnapshot;
import com.android.ahat.heapdump.Site;
@@ -24,6 +25,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.function.Predicate;
class ObjectsHandler implements AhatHandler {
private static final String OBJECTS_ID = "objects";
@@ -34,32 +36,102 @@ class ObjectsHandler implements AhatHandler {
mSnapshot = snapshot;
}
+ /**
+ * Get the list of instances that match the given site, class, and heap
+ * filters. This method is public to facilitate testing.
+ *
+ * @param site the site to get instances from
+ * @param className non-null name of the class to restrict instances to.
+ * @param subclass if true, include instances of subclasses of the named class.
+ * @param heapName name of the heap to restrict instances to. May be null to
+ * allow instances on any heap.
+ * @return list of matching instances
+ */
+ public static List<AhatInstance> getObjects(
+ Site site, String className, boolean subclass, String heapName) {
+ Predicate<AhatInstance> predicate = (x) -> {
+ return (heapName == null || x.getHeap().getName().equals(heapName))
+ && (subclass ? x.isInstanceOfClass(className) : className.equals(x.getClassName()));
+ };
+
+ List<AhatInstance> insts = new ArrayList<AhatInstance>();
+ site.getObjects(predicate, x -> insts.add(x));
+ return insts;
+ }
+
@Override
public void handle(Doc doc, Query query) throws IOException {
int id = query.getInt("id", 0);
- String className = query.get("class", null);
+ String className = query.get("class", "java.lang.Object");
String heapName = query.get("heap", null);
+ boolean subclass = (query.getInt("subclass", 0) != 0);
Site site = mSnapshot.getSite(id);
- List<AhatInstance> insts = new ArrayList<AhatInstance>();
- site.getObjects(heapName, className, insts);
+ List<AhatInstance> insts = getObjects(site, className, subclass, heapName);
Collections.sort(insts, Sort.defaultInstanceCompare(mSnapshot));
- doc.title("Objects");
+ doc.title("Instances");
+
+ // Write a description of the current settings, with links to adjust the
+ // settings, such as:
+ // Site: ROOT -
+ // Class: android.os.Binder
+ // Subclasses: excluded (switch to included)
+ // Heap: any (switch to app, image, zygote)
+ // Count: 17,424
+ doc.descriptions();
+ doc.description(DocString.text("Site"), Summarizer.summarize(site));
+ doc.description(DocString.text("Class"), DocString.text(className));
+
+ DocString subclassChoice = DocString.text(subclass ? "included" : "excluded");
+ subclassChoice.append(" (switch to ");
+ subclassChoice.appendLink(query.with("subclass", subclass ? 0 : 1),
+ DocString.text(subclass ? "excluded" : "included"));
+ subclassChoice.append(")");
+ doc.description(DocString.text("Subclasses"), subclassChoice);
+
+ DocString heapChoice = DocString.text(heapName == null ? "any" : heapName);
+ heapChoice.append(" (switch to ");
+ String comma = "";
+ for (AhatHeap heap : mSnapshot.getHeaps()) {
+ if (!heap.getName().equals(heapName)) {
+ heapChoice.append(comma);
+ heapChoice.appendLink(
+ query.with("heap", heap.getName()),
+ DocString.text(heap.getName()));
+ comma = ", ";
+ }
+ }
+ if (heapName != null) {
+ heapChoice.append(comma);
+ heapChoice.appendLink(
+ query.with("heap", null),
+ DocString.text("any"));
+ }
+ heapChoice.append(")");
+ doc.description(DocString.text("Heap"), heapChoice);
+
+ doc.description(DocString.text("Count"), DocString.format("%,14d", insts.size()));
+ doc.end();
+ doc.println(DocString.text(""));
- SizeTable.table(doc, mSnapshot.isDiffed(),
- new Column("Heap"),
- new Column("Object"));
+ if (insts.isEmpty()) {
+ doc.println(DocString.text("(none)"));
+ } else {
+ SizeTable.table(doc, mSnapshot.isDiffed(),
+ new Column("Heap"),
+ new Column("Object"));
- SubsetSelector<AhatInstance> selector = new SubsetSelector(query, OBJECTS_ID, insts);
- for (AhatInstance inst : selector.selected()) {
- AhatInstance base = inst.getBaseline();
- SizeTable.row(doc, inst.getSize(), base.getSize(),
- DocString.text(inst.getHeap().getName()),
- Summarizer.summarize(inst));
+ SubsetSelector<AhatInstance> selector = new SubsetSelector(query, OBJECTS_ID, insts);
+ for (AhatInstance inst : selector.selected()) {
+ AhatInstance base = inst.getBaseline();
+ SizeTable.row(doc, inst.getSize(), base.getSize(),
+ DocString.text(inst.getHeap().getName()),
+ Summarizer.summarize(inst));
+ }
+ SizeTable.end(doc);
+ selector.render(doc);
}
- SizeTable.end(doc);
- selector.render(doc);
}
}
diff --git a/tools/ahat/src/main/com/android/ahat/Query.java b/tools/ahat/src/main/com/android/ahat/Query.java
index 9c2783c081..5f064cdada 100644
--- a/tools/ahat/src/main/com/android/ahat/Query.java
+++ b/tools/ahat/src/main/com/android/ahat/Query.java
@@ -79,7 +79,9 @@ class Query {
/**
* Return a uri suitable for an href target that links to the current
* page, except with the named query parameter set to the new value.
- *
+ * <p>
+ * <code>value</code> may be null to remove the named query parameter.
+ * <p>
* The generated parameters will be sorted alphabetically so it is easier to
* test.
*/
@@ -92,11 +94,13 @@ class Query {
params.put(name, value);
String and = "";
for (Map.Entry<String, String> entry : params.entrySet()) {
- newQuery.append(and);
- newQuery.append(entry.getKey());
- newQuery.append('=');
- newQuery.append(entry.getValue());
- and = "&";
+ if (entry.getValue() != null) {
+ newQuery.append(and);
+ newQuery.append(entry.getKey());
+ newQuery.append('=');
+ newQuery.append(entry.getValue());
+ and = "&";
+ }
}
return DocString.uri(newQuery.toString());
}
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
index 4c60d8b2c8..0511798cad 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
@@ -107,21 +107,6 @@ public class AhatClassInstance extends AhatInstance {
return new ReferenceIterator();
}
- /**
- * Returns true if this is an instance of a (subclass of a) class with the
- * given name.
- */
- private boolean isInstanceOfClass(String className) {
- AhatClassObj cls = getClassObj();
- while (cls != null) {
- if (className.equals(cls.getName())) {
- return true;
- }
- cls = cls.getSuperClassObj();
- }
- return false;
- }
-
@Override public String asString(int maxChars) {
if (!isInstanceOfClass("java.lang.String")) {
return null;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
index 3d691c7b22..c85a057060 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
@@ -330,6 +330,25 @@ public abstract class AhatInstance implements Diffable<AhatInstance> {
}
/**
+ * Returns true if this is an instance of a (subclass of a) class with the
+ * given name.
+ *
+ * @param className the name of the class to check for
+ * @return true if this is an instance of a (subclass of a) class with the
+ * given name
+ */
+ public boolean isInstanceOfClass(String className) {
+ AhatClassObj cls = getClassObj();
+ while (cls != null) {
+ if (className.equals(cls.getName())) {
+ return true;
+ }
+ cls = cls.getSuperClassObj();
+ }
+ return false;
+ }
+
+ /**
* Returns true if the given instance is an array instance.
*
* @return true if the given instance is an array instance
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Site.java b/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
index 46a17296b7..4f0660fb50 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
@@ -23,6 +23,8 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Used to collection information about objects allocated at a particular
@@ -259,22 +261,37 @@ public class Site implements Diffable<Site> {
* every heap should be collected.
* @param className the name of the class the collected objects should
* belong to. This may be null to indicate objects of
- * every class should be collected.
+ * every class should be collected. Instances of subclasses
+ * of this class are not included.
* @param objects out parameter. A collection of objects that all
* collected objects should be added to.
*/
public void getObjects(String heapName, String className, Collection<AhatInstance> objects) {
+ Predicate<AhatInstance> predicate = x -> {
+ return (heapName == null || x.getHeap().getName().equals(heapName))
+ && (className == null || x.getClassName().equals(className));
+ };
+ getObjects(predicate, x -> objects.add(x));
+ }
+
+ /**
+ * Collects the objects allocated under this site, filtered by the given
+ * predicate.
+ * Includes objects allocated in children sites.
+ * @param predicate limit instances to those satisfying this predicate
+ * @param consumer consumer of the objects
+ */
+ public void getObjects(Predicate<AhatInstance> predicate, Consumer<AhatInstance> consumer) {
for (AhatInstance inst : mObjects) {
- if ((heapName == null || inst.getHeap().getName().equals(heapName))
- && (className == null || inst.getClassName().equals(className))) {
- objects.add(inst);
+ if (predicate.test(inst)) {
+ consumer.accept(inst);
}
}
// Recursively visit children. Recursion should be okay here because the
// stack depth is limited by a reasonable amount (128 frames or so).
for (Site child : mChildren) {
- child.getObjects(heapName, className, objects);
+ child.getObjects(predicate, consumer);
}
}
diff --git a/tools/ahat/src/test/com/android/ahat/AhatTestSuite.java b/tools/ahat/src/test/com/android/ahat/AhatTestSuite.java
index 3aa52b5bb8..abc3cc7561 100644
--- a/tools/ahat/src/test/com/android/ahat/AhatTestSuite.java
+++ b/tools/ahat/src/test/com/android/ahat/AhatTestSuite.java
@@ -29,6 +29,7 @@ import org.junit.runners.Suite;
InstanceTest.class,
NativeAllocationTest.class,
ObjectHandlerTest.class,
+ ObjectsHandlerTest.class,
OverviewHandlerTest.class,
PerformanceTest.class,
ProguardMapTest.class,
diff --git a/tools/ahat/src/test/com/android/ahat/ObjectsHandlerTest.java b/tools/ahat/src/test/com/android/ahat/ObjectsHandlerTest.java
new file mode 100644
index 0000000000..927e017ba9
--- /dev/null
+++ b/tools/ahat/src/test/com/android/ahat/ObjectsHandlerTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.ahat;
+
+import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.AhatSnapshot;
+import com.android.ahat.heapdump.Site;
+import java.io.IOException;
+import java.util.List;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ObjectsHandlerTest {
+ @Test
+ public void getObjects() throws IOException {
+ TestDump dump = TestDump.getTestDump();
+ AhatSnapshot snapshot = dump.getAhatSnapshot();
+
+ Site root = snapshot.getRootSite();
+
+ // We expect a single instance of DumpedStuff
+ List<AhatInstance> dumped = ObjectsHandler.getObjects(
+ root, "DumpedStuff", /* subclass */ false, /* heapName */ null);
+ assertEquals(1, dumped.size());
+ assertTrue(dumped.get(0).getClassName().equals("DumpedStuff"));
+
+ // We expect no direct instances of SuperDumpedStuff
+ List<AhatInstance> direct = ObjectsHandler.getObjects(
+ root, "SuperDumpedStuff", /* subclass */ false, /* heapName */ null);
+ assertTrue(direct.isEmpty());
+
+ // We expect one subclass instance of SuperDumpedStuff
+ List<AhatInstance> subclass = ObjectsHandler.getObjects(
+ root, "SuperDumpedStuff", /* subclass */ true, /* heapName */ null);
+ assertEquals(1, subclass.size());
+ assertTrue(subclass.get(0).getClassName().equals("DumpedStuff"));
+ assertEquals(dumped.get(0), subclass.get(0));
+ }
+}
diff --git a/tools/ahat/src/test/com/android/ahat/QueryTest.java b/tools/ahat/src/test/com/android/ahat/QueryTest.java
index 5bcf8eafc3..52cf963bd9 100644
--- a/tools/ahat/src/test/com/android/ahat/QueryTest.java
+++ b/tools/ahat/src/test/com/android/ahat/QueryTest.java
@@ -41,6 +41,7 @@ public class QueryTest {
assertEquals("/object?answer=43&foo=bar", query.with("answer", "43").toString());
assertEquals("/object?answer=43&foo=bar", query.with("answer", 43).toString());
assertEquals("/object?answer=42&bar=finally&foo=bar", query.with("bar", "finally").toString());
+ assertEquals("/object?answer=42", query.with("foo", null).toString());
}
@Test
@@ -55,6 +56,7 @@ public class QueryTest {
assertEquals("/object?answer=43&foo=sludge", query.with("answer", "43").toString());
assertEquals("/object?answer=42&bar=finally&foo=sludge",
query.with("bar", "finally").toString());
+ assertEquals("/object?answer=42", query.with("foo", null).toString());
}
@Test
@@ -66,5 +68,6 @@ public class QueryTest {
assertEquals(2, query.getInt("foo", 2));
assertEquals("/object?foo=sludge", query.with("foo", "sludge").toString());
assertEquals("/object?answer=43", query.with("answer", "43").toString());
+ assertEquals("/object?", query.with("foo", null).toString());
}
}
diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc
index 4eba10e764..d81f133f67 100644
--- a/tools/veridex/hidden_api_finder.cc
+++ b/tools/veridex/hidden_api_finder.cc
@@ -178,7 +178,8 @@ void HiddenApiFinder::Dump(std::ostream& os,
stats->linking_count = method_locations_.size() + field_locations_.size();
// Dump methods from hidden APIs linked against.
- for (const std::pair<std::string, std::vector<MethodReference>>& pair : method_locations_) {
+ for (const std::pair<const std::string,
+ std::vector<MethodReference>>& pair : method_locations_) {
HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(pair.first);
stats->api_counts[api_list]++;
os << "#" << ++stats->count << ": Linking " << api_list << " " << pair.first << " use(s):";
@@ -190,7 +191,8 @@ void HiddenApiFinder::Dump(std::ostream& os,
}
// Dump fields from hidden APIs linked against.
- for (const std::pair<std::string, std::vector<MethodReference>>& pair : field_locations_) {
+ for (const std::pair<const std::string,
+ std::vector<MethodReference>>& pair : field_locations_) {
HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(pair.first);
stats->api_counts[api_list]++;
os << "#" << ++stats->count << ": Linking " << api_list << " " << pair.first << " use(s):";