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

Commit 68cf7a9e authored by Joe Onorato's avatar Joe Onorato
Browse files

Parse the raw batterystats into an ActivityReport object.

For each app that appears in the batterystats data, there is an AppActivity
object (which subclasses from AppInfo, because the needs of the upcoming
PowerReport object are similar).  Inside the AppActivity, there are
ComponentActivity objects.  Each power using component has a ComponentActivity
for the fields required.  The additional Report objects in RawBatteryStats are
also added here.

This change usess modem data as a proof of concept. The exact fields in it
may evolve, even though the calculation uses tx and rx packets, the final power
calculation uses time, and putting the batterystats apportioning logic in the
batterystats handling code seems better than what we're doing here.  Anyway,
that can be iterated upon.

Test: atest frameworks/base/tools/powermodel --host
Change-Id: I2c5fce16d4fef3628d64107562d6cf9ea4edbbc2
parent 6e620876
Loading
Loading
Loading
Loading
+92 −0
Original line number Diff line number Diff line
/*
 * 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.powermodel;

import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.google.common.collect.ImmutableList;

/**
 * ActivityReport contains the summary of the activity that consumes power
 * as reported by batterystats or statsd.
 */
public class ActivityReport {
    private AppList<AppActivity> mApps;

    public ImmutableList<AppActivity> getAllApps() {
        return mApps.getAllApps();
    }

    public ImmutableList<AppActivity> getRegularApps() {
        return mApps.getRegularApps();
    }

    public List<AppActivity> findApp(String pkg) {
        return mApps.findApp(pkg);
    }

    public AppActivity findApp(SpecialApp specialApp) {
        return mApps.findApp(specialApp);
    }

    /**
     * Find a component in the GLOBAL app.
     * <p>
     * Returns null if either the global app doesn't exist (bad data?) or the component
     * doesn't exist in the global app.
     */
    public ComponentActivity findGlobalComponent(Component component) {
         final AppActivity global = mApps.findApp(SpecialApp.GLOBAL);
         if (global == null) {
             return null;
         }
         return global.getComponentActivity(component);
    }

    public static class Builder {
        private AppList.Builder<AppActivity,AppActivity.Builder> mApps = new AppList.Builder();

        public Builder() {
        }

        public ActivityReport build() {
            final ActivityReport result = new ActivityReport();
            result.mApps = mApps.build();
            return result;
        }

        public void addActivity(Component component, Collection<ComponentActivity> activities) {
            for (final ComponentActivity activity: activities) {
                addActivity(component, activity);
            }
        }

        public void addActivity(Component component, ComponentActivity activity) {
            AppActivity.Builder app = mApps.get(activity.attribution);
            if (app == null) {
                app = new AppActivity.Builder();
                app.setAttribution(activity.attribution);
                mApps.put(activity.attribution, app);
            }
            app.addComponentActivity(component, activity);
        }
    }
}
+80 −0
Original line number Diff line number Diff line
/*
 * 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.powermodel;

import java.util.HashMap;

import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

public class AppActivity extends AppInfo {

    private ImmutableMap<Component, ComponentActivity> mComponents;
    // TODO: power rails
    // private ImmutableMap<Component, PowerRailActivity> mRails;

    private AppActivity() {
    }

    /**
     * Returns the {@link ComponentActivity} for the {@link Component} provided,
     * or null if this AppActivity does not have that component.
     * @more
     * If there is no ComponentActivity for a particular Component, then
     * there was no usage associated with that app for the app in question.
     */
    public ComponentActivity getComponentActivity(Component component) {
        return mComponents.get(component);
    }

    public ImmutableSet<Component> getComponents() {
        return mComponents.keySet();
    }

    public ImmutableMap<Component,ComponentActivity> getComponentActivities() {
        return mComponents;
    }

    // TODO: power rails
    // public ComponentActivity getPowerRail(Component component) {
    //     return mComponents.get(component);
    // }
    //
    // public Set<Component> getPowerRails() {
    //     return mComponents.keySet();
    // }

    public static class Builder extends AppInfo.Builder<AppActivity> {
        private HashMap<Component, ComponentActivity> mComponents = new HashMap();
        // TODO power rails.
        
        public Builder() {
        }

        public AppActivity build() {
            final AppActivity result = new AppActivity();
            init(result);
            result.mComponents = ImmutableMap.copyOf(mComponents);
            return result;
        }

        public void addComponentActivity(Component component, ComponentActivity activity) {
            mComponents.put(component, activity);
        }
    }
}
+56 −0
Original line number Diff line number Diff line
/*
 * 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.powermodel;

class AppInfo {
    private AttributionKey mAttribution;

    protected AppInfo() {
    }

    public boolean hasPackage(String pkg) {
        return mAttribution.hasPackage(pkg);
    }

    public AttributionKey getAttribution() {
        return mAttribution;
    }

    abstract static class Builder<APP extends AppInfo> {
        private AttributionKey mAttribution;

        public Builder() {
        }

        public abstract APP build();

        protected void init(AppInfo app) {
            if (mAttribution == null) {
                throw new RuntimeException("setAttribution(AttributionKey attribution) not called");
            }
            app.mAttribution = mAttribution;
        }

        public void setAttribution(AttributionKey attribution) {
            mAttribution = attribution;
        }

        public AttributionKey getAttribution() {
            return mAttribution;
        }
    }
}
+91 −0
Original line number Diff line number Diff line
/*
 * 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.powermodel;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

class AppList<APP extends AppInfo> {
    private ImmutableList<APP> mAllApps;
    private ImmutableList<APP> mRegularApps;
    private ImmutableMap<SpecialApp,APP> mSpecialApps;

    private AppList() {
    }

    public ImmutableList<APP> getAllApps() {
        return mAllApps;
    }

    public ImmutableList<APP> getRegularApps() {
        return mRegularApps;
    }

    public List<APP> findApp(String pkg) {
        List<APP> result = new ArrayList();
        for (APP app: mRegularApps) {
            if (app.hasPackage(pkg)) {
                result.add(app);
            }
        }
        return result;
    }

    public APP findApp(SpecialApp specialApp) {
        return mSpecialApps.get(specialApp);
    }

    public static class Builder<APP extends AppInfo, BUILDER extends AppInfo.Builder<APP>> {
        private final HashMap<AttributionKey,BUILDER> mApps = new HashMap();

        public Builder() {
        }

        public AppList<APP> build() {
            final AppList<APP> result = new AppList();
            final ArrayList<APP> allApps = new ArrayList();
            final ArrayList<APP> regularApps = new ArrayList();
            final HashMap<SpecialApp,APP> specialApps = new HashMap();
            for (AppInfo.Builder<APP> app: mApps.values()) {
                final AttributionKey attribution = app.getAttribution();
                final APP appActivity = app.build();
                allApps.add(appActivity);
                if (attribution.isSpecialApp()) {
                    specialApps.put(attribution.getSpecialApp(), appActivity);
                } else {
                    regularApps.add(appActivity);
                }
            }
            result.mAllApps = ImmutableList.copyOf(allApps);
            result.mRegularApps = ImmutableList.copyOf(regularApps);
            result.mSpecialApps = ImmutableMap.copyOf(specialApps);
            return result;
        }

        public BUILDER get(AttributionKey attribution) {
            return mApps.get(attribution);
        }

        public BUILDER put(AttributionKey attribution, BUILDER app) {
            return mApps.put(attribution, app);
        }
    }
}
+74 −0
Original line number Diff line number Diff line
/*
 * 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.powermodel;

import java.io.InputStream;
import java.io.IOException;
import com.android.powermodel.component.ModemBatteryStatsReader;

public class BatteryStatsReader {
    /**
     * Construct a reader.
     */
    public BatteryStatsReader() {
    }

    /**
     * Parse a powermodel.xml file and return a PowerProfile object.
     *
     * @param stream An InputStream containing the batterystats output.
     *
     * @throws ParseException Thrown when the xml file can not be parsed.
     * @throws IOException When there is a problem reading the stream.
     */
    public static ActivityReport parse(InputStream stream) throws ParseException, IOException {
        final Parser parser = new Parser(stream);
        return parser.parse();
    }

    /**
     * Implements the reading and power model logic.
     */
    private static class Parser {
        final InputStream mStream;
        final ActivityReport mResult;
        RawBatteryStats mBs;

        /**
         * Constructor to capture the parameters to read.
         */
        Parser(InputStream stream) {
            mStream = stream;
            mResult = new ActivityReport();
        }

        /**
         * Read the stream, parse it, and apply the power model.
         * Do not call this more than once.
         */
        ActivityReport parse() throws ParseException, IOException {
            mBs = RawBatteryStats.parse(mStream);

            final ActivityReport.Builder report = new ActivityReport.Builder();

            report.addActivity(Component.MODEM, ModemBatteryStatsReader.createActivities(mBs));

            return report.build();
        }
    }
}
Loading