Loading core/java/com/android/internal/app/procstats/ProcessStats.java +1 −1 Original line number Diff line number Diff line Loading @@ -516,7 +516,7 @@ public final class ProcessStats implements Parcelable { out.writeInt((int)val); } else { int top = ~((int)((val>>32)&0x7fffffff)); int bottom = (int)(val&0xfffffff); int bottom = (int)(val&0x0ffffffffL); out.writeInt(top); out.writeInt(bottom); } Loading core/java/com/android/internal/app/procstats/SparseMappingTable.java +41 −25 Original line number Diff line number Diff line Loading @@ -68,11 +68,8 @@ public class SparseMappingTable { * A table of data as stored in a SparseMappingTable. */ public static class Table { // When mSequence is this this our data better be empty private static final int UNINITIALIZED_SEQUENCE = -1; private SparseMappingTable mParent; private int mSequence = UNINITIALIZED_SEQUENCE; private int mSequence = 1; private int[] mTable; private int mSize; Loading Loading @@ -119,12 +116,6 @@ public class SparseMappingTable { * but should be considered opaque to the caller. */ public int getOrAddKey(byte id, int count) { // This is the only place we add data to mParent.mLongs, so this is the time // to update our sequence to match there. if (mSequence == UNINITIALIZED_SEQUENCE) { mSequence = mParent.mSequence; } assertConsistency(); final int idx = binarySearch(id); Loading Loading @@ -311,7 +302,7 @@ public class SparseMappingTable { // Reset our sequence number. This will make all read/write calls // start to fail, and then when we re-allocate it will be re-synced // to that of mParent. mSequence = UNINITIALIZED_SEQUENCE; mSequence = mParent.mSequence; } /** Loading Loading @@ -377,27 +368,19 @@ public class SparseMappingTable { // Original bug: b/27045736 // New bug: b/27960286 if (false) { // Assert that our sequence number has been initialized. If it hasn't // that means someone tried to read or write data without allocating it // since we were created or reset. if (mSequence == UNINITIALIZED_SEQUENCE) { logOrThrow("mSequence == UNINITIALIZED_SEQUENCE in" + " SparseMappingTable.Table. -- " + dumpInternalState()); return; } // Assert that our sequence number matches mParent's. If it isn't that means // we have been reset and our // we have been reset and our. If our sequence is UNITIALIZED_SEQUENCE, then // it's possible that everything is working fine and we just haven't been // written to since the last resetTable(). if (mSequence != mParent.mSequence) { if (mSequence < mParent.mSequence) { logOrThrow("Sequence mismatch. SparseMappingTable.resetTable()" logOrThrow("Sequence mismatch. SparseMappingTable.reset()" + " called but not Table.resetTable() -- " + dumpInternalState()); return; } else if (mSequence > mParent.mSequence) { logOrThrow("Sequence mismatch. Table.resetTable()" + " called but not SparseMappingTable.resetTable() -- " + " called but not SparseMappingTable.reset() -- " + dumpInternalState()); return; } Loading Loading @@ -494,6 +477,10 @@ public class SparseMappingTable { } } public SparseMappingTable() { mLongs.add(new long[ARRAY_SIZE]); } /** * Wipe out all the data. */ Loading Loading @@ -544,6 +531,35 @@ public class SparseMappingTable { } } /** * Return a string for debugging. */ public String dumpInternalState(boolean includeData) { final StringBuilder sb = new StringBuilder(); sb.append("SparseMappingTable{"); sb.append("mSequence="); sb.append(mSequence); sb.append(" mNextIndex="); sb.append(mNextIndex); sb.append(" mLongs.size="); final int N = mLongs.size(); sb.append(N); sb.append("\n"); if (includeData) { for (int i=0; i<N; i++) { final long[] array = mLongs.get(i); for (int j=0; j<array.length; j++) { if (i == N-1 && j == mNextIndex) { break; } sb.append(String.format(" %4d %d 0x%016x %-19d\n", i, j, array[j], array[j])); } } } sb.append("}"); return sb.toString(); } /** * Write the long array to the parcel in a compacted form. Does not allow negative * values in the array. Loading @@ -559,7 +575,7 @@ public class SparseMappingTable { out.writeInt((int)val); } else { int top = ~((int)((val>>32)&0x7fffffff)); int bottom = (int)(val&0xfffffff); int bottom = (int)(val&0x0ffffffffL); out.writeInt(top); out.writeInt(bottom); } Loading core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java 0 → 100644 +209 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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.internal.app.procstats; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import android.os.BatteryStats; import android.os.Parcel; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import junit.framework.Assert; import junit.framework.TestCase; import org.mockito.Mockito; /** * Provides test cases for SparseMappingTable. */ public class SparseMappingTableTest extends TestCase { private static final String TAG = "SparseMappingTableTest"; final byte ID1 = 1; final byte ID2 = 2; final long VALUE1 = 100; final long VALUE2 = 10000000000L; /** * Test the parceling and unparceling logic when there is no data. */ @SmallTest public void testParcelingEmpty() throws Exception { final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); final Parcel dataParcel = Parcel.obtain(); data.writeToParcel(dataParcel); final Parcel tableParcel = Parcel.obtain(); table.writeToParcel(tableParcel); dataParcel.setDataPosition(0); final SparseMappingTable data1 = new SparseMappingTable(); data1.readFromParcel(dataParcel); Assert.assertEquals(0, dataParcel.dataAvail()); dataParcel.recycle(); tableParcel.setDataPosition(0); final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); table1.readFromParcel(tableParcel); Assert.assertEquals(0, tableParcel.dataAvail()); tableParcel.recycle(); } /** * Test the parceling and unparceling logic. */ @SmallTest public void testParceling() throws Exception { int key; final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); key = table.getOrAddKey(ID1, 1); table.setValue(key, VALUE1); key = table.getOrAddKey(ID2, 1); table.setValue(key, VALUE2); final Parcel dataParcel = Parcel.obtain(); data.writeToParcel(dataParcel); final Parcel tableParcel = Parcel.obtain(); table.writeToParcel(tableParcel); dataParcel.setDataPosition(0); final SparseMappingTable data1 = new SparseMappingTable(); data1.readFromParcel(dataParcel); Assert.assertEquals(0, dataParcel.dataAvail()); dataParcel.recycle(); tableParcel.setDataPosition(0); final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); table1.readFromParcel(tableParcel); Assert.assertEquals(0, tableParcel.dataAvail()); tableParcel.recycle(); key = table1.getKey(ID1); Assert.assertEquals(VALUE1, table1.getValue(key)); key = table1.getKey(ID2); Assert.assertEquals(VALUE2, table1.getValue(key)); } /** * Test that after resetting you can still read data, you just get no values. */ @SmallTest public void testParcelingWithReset() throws Exception { int key; final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); key = table.getOrAddKey(ID1, 1); table.setValue(key, VALUE1); data.reset(); table.resetTable(); key = table.getOrAddKey(ID2, 1); table.setValue(key, VALUE2); Log.d(TAG, "before: " + data.dumpInternalState(true)); Log.d(TAG, "before: " + table.dumpInternalState()); final Parcel dataParcel = Parcel.obtain(); data.writeToParcel(dataParcel); final Parcel tableParcel = Parcel.obtain(); table.writeToParcel(tableParcel); dataParcel.setDataPosition(0); final SparseMappingTable data1 = new SparseMappingTable(); data1.readFromParcel(dataParcel); Assert.assertEquals(0, dataParcel.dataAvail()); dataParcel.recycle(); tableParcel.setDataPosition(0); final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); table1.readFromParcel(tableParcel); Assert.assertEquals(0, tableParcel.dataAvail()); tableParcel.recycle(); key = table1.getKey(ID1); Assert.assertEquals(SparseMappingTable.INVALID_KEY, key); key = table1.getKey(ID2); Assert.assertEquals(VALUE2, table1.getValue(key)); Log.d(TAG, " after: " + data1.dumpInternalState(true)); Log.d(TAG, " after: " + table1.dumpInternalState()); } /** * Test that it fails if you reset the data and not the table. * * Resetting the table and not the data is basically okay. The data in the * SparseMappingTable will be leaked. */ @SmallTest public void testResetDataOnlyFails() throws Exception { int key; final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); key = table.getOrAddKey(ID1, 1); table.setValue(key, VALUE1); Assert.assertEquals(VALUE1, table.getValue(key)); data.reset(); try { table.getValue(key); throw new Exception("Exception not thrown after mismatched reset calls."); } catch (RuntimeException ex) { // Good } } /** * Test that trying to get data that you didn't add fails correctly. */ @SmallTest public void testInvalidKey() throws Exception { int key; final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); key = table.getKey(ID1); // The key should be INVALID_KEY Assert.assertEquals(SparseMappingTable.INVALID_KEY, key); // If you get the value with getValueForId you get 0. Assert.assertEquals(0, table.getValueForId(ID1)); } } Loading
core/java/com/android/internal/app/procstats/ProcessStats.java +1 −1 Original line number Diff line number Diff line Loading @@ -516,7 +516,7 @@ public final class ProcessStats implements Parcelable { out.writeInt((int)val); } else { int top = ~((int)((val>>32)&0x7fffffff)); int bottom = (int)(val&0xfffffff); int bottom = (int)(val&0x0ffffffffL); out.writeInt(top); out.writeInt(bottom); } Loading
core/java/com/android/internal/app/procstats/SparseMappingTable.java +41 −25 Original line number Diff line number Diff line Loading @@ -68,11 +68,8 @@ public class SparseMappingTable { * A table of data as stored in a SparseMappingTable. */ public static class Table { // When mSequence is this this our data better be empty private static final int UNINITIALIZED_SEQUENCE = -1; private SparseMappingTable mParent; private int mSequence = UNINITIALIZED_SEQUENCE; private int mSequence = 1; private int[] mTable; private int mSize; Loading Loading @@ -119,12 +116,6 @@ public class SparseMappingTable { * but should be considered opaque to the caller. */ public int getOrAddKey(byte id, int count) { // This is the only place we add data to mParent.mLongs, so this is the time // to update our sequence to match there. if (mSequence == UNINITIALIZED_SEQUENCE) { mSequence = mParent.mSequence; } assertConsistency(); final int idx = binarySearch(id); Loading Loading @@ -311,7 +302,7 @@ public class SparseMappingTable { // Reset our sequence number. This will make all read/write calls // start to fail, and then when we re-allocate it will be re-synced // to that of mParent. mSequence = UNINITIALIZED_SEQUENCE; mSequence = mParent.mSequence; } /** Loading Loading @@ -377,27 +368,19 @@ public class SparseMappingTable { // Original bug: b/27045736 // New bug: b/27960286 if (false) { // Assert that our sequence number has been initialized. If it hasn't // that means someone tried to read or write data without allocating it // since we were created or reset. if (mSequence == UNINITIALIZED_SEQUENCE) { logOrThrow("mSequence == UNINITIALIZED_SEQUENCE in" + " SparseMappingTable.Table. -- " + dumpInternalState()); return; } // Assert that our sequence number matches mParent's. If it isn't that means // we have been reset and our // we have been reset and our. If our sequence is UNITIALIZED_SEQUENCE, then // it's possible that everything is working fine and we just haven't been // written to since the last resetTable(). if (mSequence != mParent.mSequence) { if (mSequence < mParent.mSequence) { logOrThrow("Sequence mismatch. SparseMappingTable.resetTable()" logOrThrow("Sequence mismatch. SparseMappingTable.reset()" + " called but not Table.resetTable() -- " + dumpInternalState()); return; } else if (mSequence > mParent.mSequence) { logOrThrow("Sequence mismatch. Table.resetTable()" + " called but not SparseMappingTable.resetTable() -- " + " called but not SparseMappingTable.reset() -- " + dumpInternalState()); return; } Loading Loading @@ -494,6 +477,10 @@ public class SparseMappingTable { } } public SparseMappingTable() { mLongs.add(new long[ARRAY_SIZE]); } /** * Wipe out all the data. */ Loading Loading @@ -544,6 +531,35 @@ public class SparseMappingTable { } } /** * Return a string for debugging. */ public String dumpInternalState(boolean includeData) { final StringBuilder sb = new StringBuilder(); sb.append("SparseMappingTable{"); sb.append("mSequence="); sb.append(mSequence); sb.append(" mNextIndex="); sb.append(mNextIndex); sb.append(" mLongs.size="); final int N = mLongs.size(); sb.append(N); sb.append("\n"); if (includeData) { for (int i=0; i<N; i++) { final long[] array = mLongs.get(i); for (int j=0; j<array.length; j++) { if (i == N-1 && j == mNextIndex) { break; } sb.append(String.format(" %4d %d 0x%016x %-19d\n", i, j, array[j], array[j])); } } } sb.append("}"); return sb.toString(); } /** * Write the long array to the parcel in a compacted form. Does not allow negative * values in the array. Loading @@ -559,7 +575,7 @@ public class SparseMappingTable { out.writeInt((int)val); } else { int top = ~((int)((val>>32)&0x7fffffff)); int bottom = (int)(val&0xfffffff); int bottom = (int)(val&0x0ffffffffL); out.writeInt(top); out.writeInt(bottom); } Loading
core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java 0 → 100644 +209 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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.internal.app.procstats; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import android.os.BatteryStats; import android.os.Parcel; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import junit.framework.Assert; import junit.framework.TestCase; import org.mockito.Mockito; /** * Provides test cases for SparseMappingTable. */ public class SparseMappingTableTest extends TestCase { private static final String TAG = "SparseMappingTableTest"; final byte ID1 = 1; final byte ID2 = 2; final long VALUE1 = 100; final long VALUE2 = 10000000000L; /** * Test the parceling and unparceling logic when there is no data. */ @SmallTest public void testParcelingEmpty() throws Exception { final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); final Parcel dataParcel = Parcel.obtain(); data.writeToParcel(dataParcel); final Parcel tableParcel = Parcel.obtain(); table.writeToParcel(tableParcel); dataParcel.setDataPosition(0); final SparseMappingTable data1 = new SparseMappingTable(); data1.readFromParcel(dataParcel); Assert.assertEquals(0, dataParcel.dataAvail()); dataParcel.recycle(); tableParcel.setDataPosition(0); final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); table1.readFromParcel(tableParcel); Assert.assertEquals(0, tableParcel.dataAvail()); tableParcel.recycle(); } /** * Test the parceling and unparceling logic. */ @SmallTest public void testParceling() throws Exception { int key; final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); key = table.getOrAddKey(ID1, 1); table.setValue(key, VALUE1); key = table.getOrAddKey(ID2, 1); table.setValue(key, VALUE2); final Parcel dataParcel = Parcel.obtain(); data.writeToParcel(dataParcel); final Parcel tableParcel = Parcel.obtain(); table.writeToParcel(tableParcel); dataParcel.setDataPosition(0); final SparseMappingTable data1 = new SparseMappingTable(); data1.readFromParcel(dataParcel); Assert.assertEquals(0, dataParcel.dataAvail()); dataParcel.recycle(); tableParcel.setDataPosition(0); final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); table1.readFromParcel(tableParcel); Assert.assertEquals(0, tableParcel.dataAvail()); tableParcel.recycle(); key = table1.getKey(ID1); Assert.assertEquals(VALUE1, table1.getValue(key)); key = table1.getKey(ID2); Assert.assertEquals(VALUE2, table1.getValue(key)); } /** * Test that after resetting you can still read data, you just get no values. */ @SmallTest public void testParcelingWithReset() throws Exception { int key; final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); key = table.getOrAddKey(ID1, 1); table.setValue(key, VALUE1); data.reset(); table.resetTable(); key = table.getOrAddKey(ID2, 1); table.setValue(key, VALUE2); Log.d(TAG, "before: " + data.dumpInternalState(true)); Log.d(TAG, "before: " + table.dumpInternalState()); final Parcel dataParcel = Parcel.obtain(); data.writeToParcel(dataParcel); final Parcel tableParcel = Parcel.obtain(); table.writeToParcel(tableParcel); dataParcel.setDataPosition(0); final SparseMappingTable data1 = new SparseMappingTable(); data1.readFromParcel(dataParcel); Assert.assertEquals(0, dataParcel.dataAvail()); dataParcel.recycle(); tableParcel.setDataPosition(0); final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1); table1.readFromParcel(tableParcel); Assert.assertEquals(0, tableParcel.dataAvail()); tableParcel.recycle(); key = table1.getKey(ID1); Assert.assertEquals(SparseMappingTable.INVALID_KEY, key); key = table1.getKey(ID2); Assert.assertEquals(VALUE2, table1.getValue(key)); Log.d(TAG, " after: " + data1.dumpInternalState(true)); Log.d(TAG, " after: " + table1.dumpInternalState()); } /** * Test that it fails if you reset the data and not the table. * * Resetting the table and not the data is basically okay. The data in the * SparseMappingTable will be leaked. */ @SmallTest public void testResetDataOnlyFails() throws Exception { int key; final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); key = table.getOrAddKey(ID1, 1); table.setValue(key, VALUE1); Assert.assertEquals(VALUE1, table.getValue(key)); data.reset(); try { table.getValue(key); throw new Exception("Exception not thrown after mismatched reset calls."); } catch (RuntimeException ex) { // Good } } /** * Test that trying to get data that you didn't add fails correctly. */ @SmallTest public void testInvalidKey() throws Exception { int key; final SparseMappingTable data = new SparseMappingTable(); final SparseMappingTable.Table table = new SparseMappingTable.Table(data); key = table.getKey(ID1); // The key should be INVALID_KEY Assert.assertEquals(SparseMappingTable.INVALID_KEY, key); // If you get the value with getValueForId you get 0. Assert.assertEquals(0, table.getValueForId(ID1)); } }