最近做了一个采集设备信息的应用,其中获取应用打开次数以及cpu信息还是挺有意思的,所以在此mark下吧。
一、获取应用打开次数
获取android设备中应用信息的类是UsageStats.java类(官网见https://developer.android.com/reference/android/app/usage/UsageStatsManager.html):
/**
* Copyright (C) 2014 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 android.app.usage;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Contains usage statistics for an app package for a specific
* time range.
*/
public final class UsageStats implements Parcelable {
/**
* {@hide}
*/
public String mPackageName;
/**
* {@hide}
*/
public long mBeginTimeStamp;
/**
* {@hide}
*/
public long mEndTimeStamp;
/**
* Last time used by the user with an explicit action (notification, activity launch).
* {@hide}
*/
public long mLastTimeUsed;
/**
* {@hide}
*/
public long mTotalTimeInForeground;
/**
* {@hide}
*/
public int mLaunchCount;
/**
* {@hide}
*/
public int mLastEvent;
/**
* {@hide}
*/
public UsageStats() {
}
public UsageStats(UsageStats stats) {
mPackageName = stats.mPackageName;
mBeginTimeStamp = stats.mBeginTimeStamp;
mEndTimeStamp = stats.mEndTimeStamp;
mLastTimeUsed = stats.mLastTimeUsed;
mTotalTimeInForeground = stats.mTotalTimeInForeground;
mLaunchCount = stats.mLaunchCount;
mLastEvent = stats.mLastEvent;
}
public String getPackageName() {
return mPackageName;
}
/**
* Get the beginning of the time range this {@link android.app.usage.UsageStats} represents,
* measured in milliseconds since the epoch.
* <p/>
* See {@link System#currentTimeMillis()}.
*/
public long getFirstTimeStamp() {
return mBeginTimeStamp;
}
/**
* Get the end of the time range this {@link android.app.usage.UsageStats} represents,
* measured in milliseconds since the epoch.
* <p/>
* See {@link System#currentTimeMillis()}.
*/
public long getLastTimeStamp() {
return mEndTimeStamp;
}
/**
* Get the last time this package was used, measured in milliseconds since the epoch.
* <p/>
* See {@link System#currentTimeMillis()}.
*/
public long getLastTimeUsed() {
return mLastTimeUsed;
}
/**
* Get the total time this package spent in the foreground, measured in milliseconds.
*/
public long getTotalTimeInForeground() {
return mTotalTimeInForeground;
}
/**
* Add the statistics from the right {@link UsageStats} to the left. The package name for
* both {@link UsageStats} objects must be the same.
* @param right The {@link UsageStats} object to merge into this one.
* @throws java.lang.IllegalArgumentException if the package names of the two
* {@link UsageStats} objects are different.
*/
public void add(UsageStats right) {
if (!mPackageName.equals(right.mPackageName)) {
throw new IllegalArgumentException("Can't merge UsageStats for package '" +
mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
}
if (right.mBeginTimeStamp > mBeginTimeStamp) {
// The incoming UsageStat begins after this one, so use its last time used fields
// as the source of truth.
// We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
// regards to their mEndTimeStamp.
mLastEvent = right.mLastEvent;
mLastTimeUsed = right.mLastTimeUsed;
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
mLaunchCount += right.mLaunchCount;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPackageName);
dest.writeLong(mBeginTimeStamp);
dest.writeLong(mEndTimeStamp);
dest.writeLong(mLastTimeUsed);
dest.writeLong(mTotalTimeInForeground);
dest.writeInt(mLaunchCount);
dest.writeInt(mLastEvent);
}
public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
@Override
public UsageStats createFromParcel(Parcel in) {
UsageStats stats = new UsageStats();
stats.mPackageName = in.readString();
stats.mBeginTimeStamp = in.readLong();
stats.mEndTimeStamp = in.readLong();
stats.mLastTimeUsed = in.readLong();
stats.mTotalTimeInForeground = in.readLong();
stats.mLaunchCount = in.readInt();
stats.mLastEvent = in.readInt();
return stats;
}
@Override
public UsageStats[] newArray(int size) {
return new UsageStats[size];
}
};
}
从源码中可以看出,获取应用的列表可以就可以通过现成的方法获取包名、上次使用时间戳、上次使用时间、总的前台使用时间等信息,但却没有获取使用次数的方法,这就需要使用反射了。
UsageStatsManager m = (UsageStatsManager) context.getSystemService(USAGE_STATS_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
long endt = calendar.getTimeInMillis(); //结束时间
calendar.add(Calendar.HOUR_OF_DAY, -1); //时间间隔为一天
long statt = calendar.getTimeInMillis();
List<UsageStats> list = m.queryUsageStats(UsageStatsManager.INTERVAL_BEST, statt, endt);
for (UsageStats stats : list) {
stringBuffer.append(stats.getPackageName() + "##开始时间:" + stats.getFirstTimeStamp() + "##结束时间:" + stats.getLastTimeStamp() + "总运行时间:" + stats.getTotalTimeInForeground() + "\n");
try {
**int count = stats.getClass().getDeclaredField("mLaunchCount").getInt(stats);**
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
当然啦,还是只有系统权限的应用才能获取到应用列表,同时需要在manifest文件中声明权限
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
当时出现了一个问题,那就是必须在activity中才能获取到应用打开次数,在其他类里面获取到的次数总是为0,还奇怪耶。
二、 获取cpu信息
开始是通过读取“/proc/stat”文件的信息来获取cpu数目的,但是在展讯7.0手机上发现,有些时候并不是所有cpu都会打印出来,参考了下安兔兔,发现有些cpu在休眠,又查找了下,发现可以通过“/sys/devices/system/cpu/”目录下cpu的数量来查看设备cpu核数。
继续cd到cpu3下可以看出有时没有current_freq文件,这应该是真的在休眠了吧。
获取cpu数量的代码如下:
public static int getNumCores() {
//Private Class to display only CPU devices in the directory listing
class CpuFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
//Check if filename is "cpu", followed by a single digit number
if (Pattern.matches("cpu[0-9]+", pathname.getName())) {
return true;
}
return false;
}
}
try {
//Get directory containing CPU info
File dir = new File("/sys/devices/system/cpu/");
//Filter to only list the devices we care about
File[] files = dir.listFiles(new CpuFilter());
Trace.d(TAG, "CPU Count: " + files.length);
//Return the number of cores (virtual CPU devices)
return files.length;
} catch (Exception e) {
//Print exception
Trace.d(TAG, "CPU Count: Failed.");
e.printStackTrace();
//Default to return 1 core
return 1;
}
}