Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65adfeec authored by Joe Onorato's avatar Joe Onorato
Browse files

Add some tests for procstats, and fix some bugs that the tests uncovered.

Bug: 27045736
Change-Id: Ia910730c5a3a899c89aa63dd7ab48be62cf9cfef
parent 1ee2dd2f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
            }
+41 −25
Original line number Diff line number Diff line
@@ -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;

@@ -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);
@@ -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;
        }

        /**
@@ -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;
                    }
@@ -494,6 +477,10 @@ public class SparseMappingTable {
        }
    }

    public SparseMappingTable() {
        mLongs.add(new long[ARRAY_SIZE]);
    }

    /**
     * Wipe out all the data.
     */
@@ -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.
@@ -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);
            }
+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));
    }
}