New "app ops" service.

Initial implementation, tracking use of the vibrator, GPS,
and location reports.

Also includes an update to battery stats to also keep track of
vibrator usage (since I had to be in the vibrator code anyway
to instrument it).

The service itself is only half-done.  Currently no API to
retrieve the data (which once there will allow us to show you
which apps are currently causing the GPS to run and who has
recently accessed your location), it doesn't persist its data
like it should, and no way to tell it to reject app requests
for various operations.

But hey, it's a start!

Change-Id: I05b8d76cc4a4f7f37bc758c1701f51f9e0550e15
This commit is contained in:
Dianne Hackborn
2012-12-11 16:34:47 -08:00
parent 2e9f65f978
commit a06de0f29b
25 changed files with 970 additions and 104 deletions

View File

@@ -166,6 +166,7 @@ LOCAL_SRC_FILES += \
core/java/android/speech/IRecognitionService.aidl \
core/java/android/speech/tts/ITextToSpeechCallback.aidl \
core/java/android/speech/tts/ITextToSpeechService.aidl \
core/java/com/android/internal/app/IAppOpsService.aidl \
core/java/com/android/internal/app/IBatteryStats.aidl \
core/java/com/android/internal/app/IUsageStats.aidl \
core/java/com/android/internal/app/IMediaContainerService.aidl \

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2012 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;
import com.android.internal.app.IAppOpsService;
import android.content.Context;
import android.os.Process;
import android.os.RemoteException;
/** @hide */
public class AppOpsManager {
final Context mContext;
final IAppOpsService mService;
public static final int MODE_ALLOWED = 0;
public static final int MODE_IGNORED = 1;
public static final int MODE_ERRORED = 2;
public static final int OP_LOCATION = 0;
public static final int OP_GPS = 1;
public static final int OP_VIBRATE = 2;
public static String opToString(int op) {
switch (op) {
case OP_LOCATION: return "LOCATION";
case OP_GPS: return "GPS";
case OP_VIBRATE: return "VIBRATE";
default: return "Unknown(" + op + ")";
}
}
public AppOpsManager(Context context, IAppOpsService service) {
mContext = context;
mService = service;
}
public int noteOp(int op, int uid, String packageName) {
try {
int mode = mService.noteOperation(op, uid, packageName);
if (mode == MODE_ERRORED) {
throw new SecurityException("Operation not allowed");
}
return mode;
} catch (RemoteException e) {
}
return MODE_IGNORED;
}
public int noteOpNoThrow(int op, int uid, String packageName) {
try {
return mService.noteOperation(op, uid, packageName);
} catch (RemoteException e) {
}
return MODE_IGNORED;
}
public int noteOp(int op) {
return noteOp(op, Process.myUid(), mContext.getPackageName());
}
public int startOp(int op, int uid, String packageName) {
try {
int mode = mService.startOperation(op, uid, packageName);
if (mode == MODE_ERRORED) {
throw new SecurityException("Operation not allowed");
}
return mode;
} catch (RemoteException e) {
}
return MODE_IGNORED;
}
public int startOpNoThrow(int op, int uid, String packageName) {
try {
return mService.startOperation(op, uid, packageName);
} catch (RemoteException e) {
}
return MODE_IGNORED;
}
public int startOp(int op) {
return startOp(op, Process.myUid(), mContext.getPackageName());
}
public void finishOp(int op, int uid, String packageName) {
try {
mService.finishOperation(op, uid, packageName);
} catch (RemoteException e) {
}
}
public void finishOp(int op) {
finishOp(op, Process.myUid(), mContext.getPackageName());
}
}

View File

@@ -141,6 +141,21 @@ final class ApplicationPackageManager extends PackageManager {
throw new NameNotFoundException(packageName);
}
@Override
public int getPackageUid(String packageName, int userHandle)
throws NameNotFoundException {
try {
int uid = mPM.getPackageUid(packageName, userHandle);
if (uid >= 0) {
return uid;
}
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
throw new NameNotFoundException(packageName);
}
@Override
public PermissionInfo getPermissionInfo(String name, int flags)
throws NameNotFoundException {

View File

@@ -47,11 +47,9 @@ import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.hardware.ISerialManager;
import android.hardware.SensorManager;
import android.hardware.SerialManager;
import android.hardware.SystemSensorManager;
import android.hardware.display.DisplayManager;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbManager;
@@ -109,6 +107,8 @@ import android.view.textservice.TextServicesManager;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.app.admin.DevicePolicyManager;
import com.android.internal.app.IAppOpsService;
import com.android.internal.os.IDropBoxManagerService;
import java.io.File;
@@ -499,7 +499,7 @@ class ContextImpl extends Context {
registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new SystemVibrator();
return new SystemVibrator(ctx);
}});
registerService(WALLPAPER_SERVICE, WALLPAPER_FETCHER);
@@ -530,11 +530,18 @@ class ContextImpl extends Context {
}});
registerService(USER_SERVICE, new ServiceFetcher() {
public Object getService(ContextImpl ctx) {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(USER_SERVICE);
IUserManager service = IUserManager.Stub.asInterface(b);
return new UserManager(ctx, service);
}});
registerService(APP_OPS_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(APP_OPS_SERVICE);
IAppOpsService service = IAppOpsService.Stub.asInterface(b);
return new AppOpsManager(ctx, service);
}});
}
static ContextImpl getImpl(Context context) {

View File

@@ -2288,6 +2288,18 @@ public abstract class Context {
*/
public static final String USER_SERVICE = "user";
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.app.AppOpsManager} for tracking application operations
* on the device.
*
* @see #getSystemService
* @see android.app.AppOpsManager
*
* @hide
*/
public static final String APP_OPS_SERVICE = "appops";
/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.

View File

@@ -1279,6 +1279,22 @@ public abstract class PackageManager {
public abstract int[] getPackageGids(String packageName)
throws NameNotFoundException;
/**
* @hide Return the uid associated with the given package name for the
* given user.
*
* <p>Throws {@link NameNotFoundException} if a package with the given
* name can not be found on the system.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
* @param userHandle The user handle identifier to look up the package under.
*
* @return Returns an integer uid who owns the given package name.
*/
public abstract int getPackageUid(String packageName, int userHandle)
throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular permission.
*

View File

@@ -92,6 +92,11 @@ public abstract class BatteryStats implements Parcelable {
*/
public static final int VIDEO_TURNED_ON = 8;
/**
* A constant indicating a vibrator on timer
*/
public static final int VIBRATOR_ON = 9;
/**
* Include all of the data in the stats, including previously saved data.
*/
@@ -131,6 +136,7 @@ public abstract class BatteryStats implements Parcelable {
private static final String APK_DATA = "apk";
private static final String PROCESS_DATA = "pr";
private static final String SENSOR_DATA = "sr";
private static final String VIBRATOR_DATA = "vib";
private static final String WAKELOCK_DATA = "wl";
private static final String KERNEL_WAKELOCK_DATA = "kwl";
private static final String NETWORK_DATA = "nt";
@@ -277,6 +283,7 @@ public abstract class BatteryStats implements Parcelable {
int which);
public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
public abstract long getVideoTurnedOnTime(long batteryRealtime, int which);
public abstract Timer getVibratorOnTimer();
/**
* Note that these must match the constants in android.os.PowerManager.
@@ -1395,6 +1402,16 @@ public abstract class BatteryStats implements Parcelable {
}
}
Timer vibTimer = u.getVibratorOnTimer();
if (vibTimer != null) {
// Convert from microseconds to milliseconds with rounding
long totalTime = (vibTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
int count = vibTimer.getCountLocked(which);
if (totalTime != 0) {
dumpLine(pw, uid, category, VIBRATOR_DATA, totalTime, count);
}
}
Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
if (processStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
@@ -1919,6 +1936,26 @@ public abstract class BatteryStats implements Parcelable {
}
}
Timer vibTimer = u.getVibratorOnTimer();
if (vibTimer != null) {
// Convert from microseconds to milliseconds with rounding
long totalTime = (vibTimer.getTotalTimeLocked(
batteryRealtime, which) + 500) / 1000;
int count = vibTimer.getCountLocked(which);
//timer.logState();
if (totalTime != 0) {
sb.setLength(0);
sb.append(prefix);
sb.append(" Vibrator: ");
formatTimeMs(sb, totalTime);
sb.append("realtime (");
sb.append(count);
sb.append(" times)");
pw.println(sb.toString());
uidActivity = true;
}
}
Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
if (processStats.size() > 0) {
for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent

View File

@@ -20,8 +20,8 @@ package android.os;
interface IVibratorService
{
boolean hasVibrator();
void vibrate(long milliseconds, IBinder token);
void vibratePattern(in long[] pattern, int repeat, IBinder token);
void vibrate(String packageName, long milliseconds, IBinder token);
void vibratePattern(String packageName, in long[] pattern, int repeat, IBinder token);
void cancelVibrate(IBinder token);
}

View File

@@ -16,6 +16,7 @@
package android.os;
import android.content.Context;
import android.util.Log;
/**
@@ -26,10 +27,18 @@ import android.util.Log;
public class SystemVibrator extends Vibrator {
private static final String TAG = "Vibrator";
private final String mPackageName;
private final IVibratorService mService;
private final Binder mToken = new Binder();
public SystemVibrator() {
mPackageName = null;
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
}
public SystemVibrator(Context context) {
mPackageName = context.getPackageName();
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
}
@@ -54,7 +63,7 @@ public class SystemVibrator extends Vibrator {
return;
}
try {
mService.vibrate(milliseconds, mToken);
mService.vibrate(mPackageName, milliseconds, mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
}
@@ -71,7 +80,7 @@ public class SystemVibrator extends Vibrator {
// anyway
if (repeat < pattern.length) {
try {
mService.vibratePattern(pattern, repeat, mToken);
mService.vibratePattern(mPackageName, pattern, repeat, mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
}

View File

@@ -16,6 +16,8 @@
package android.os;
import java.io.PrintWriter;
/**
* Representation of a user on the device.
*/
@@ -151,6 +153,50 @@ public final class UserHandle implements Parcelable {
- Process.FIRST_APPLICATION_UID;
}
/**
* Generate a text representation of the uid, breaking out its individual
* components -- user, app, isolated, etc.
* @hide
*/
public static void formatUid(StringBuilder sb, int uid) {
if (uid < Process.FIRST_APPLICATION_UID) {
sb.append(uid);
} else {
sb.append('u');
sb.append(getUserId(uid));
final int appId = getAppId(uid);
if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
sb.append('i');
sb.append(appId - Process.FIRST_ISOLATED_UID);
} else {
sb.append('a');
sb.append(appId);
}
}
}
/**
* Generate a text representation of the uid, breaking out its individual
* components -- user, app, isolated, etc.
* @hide
*/
public static void formatUid(PrintWriter pw, int uid) {
if (uid < Process.FIRST_APPLICATION_UID) {
pw.print(uid);
} else {
pw.print('u');
pw.print(getUserId(uid));
final int appId = getAppId(uid);
if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
pw.print('i');
pw.print(appId - Process.FIRST_ISOLATED_UID);
} else {
pw.print('a');
pw.print(appId);
}
}
}
/**
* Returns the user id of the current process
* @return user id of the current process

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2012 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;
interface IAppOpsService {
int noteOperation(int code, int uid, String packageName);
int startOperation(int code, int uid, String packageName);
void finishOperation(int code, int uid, String packageName);
int noteTimedOperation(int code, int uid, String packageName, int duration);
void earlyFinishOperation(int code, int uid, String packageName);
}

View File

@@ -37,6 +37,8 @@ interface IBatteryStats {
void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type);
void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
void noteVibratorOn(int uid, long durationMillis);
void noteVibratorOff(int uid);
void noteStartGps(int uid);
void noteStopGps(int uid);
void noteScreenOn();

View File

@@ -16,14 +16,11 @@
package com.android.internal.os;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.UID_ALL;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
import android.os.BatteryManager;
@@ -49,7 +46,6 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import com.android.internal.R;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.JournaledFile;
import com.google.android.collect.Sets;
@@ -87,7 +83,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
private static final int VERSION = 62 + (USE_OLD_HISTORY ? 1000 : 0);
private static final int VERSION = 64 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -356,8 +352,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public static interface Unpluggable {
void unplug(long batteryUptime, long batteryRealtime);
void plug(long batteryUptime, long batteryRealtime);
void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime);
void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime);
}
/**
@@ -392,12 +388,12 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mUnpluggedCount);
}
public void unplug(long batteryUptime, long batteryRealtime) {
public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
mUnpluggedCount = mPluggedCount;
mCount.set(mPluggedCount);
}
public void plug(long batteryUptime, long batteryRealtime) {
public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
mPluggedCount = mCount.get();
}
@@ -587,7 +583,7 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(mUnpluggedTime);
}
public void unplug(long batteryUptime, long batteryRealtime) {
public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
if (DEBUG && mType < 0) {
Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime
+ " old mUnpluggedTime=" + mUnpluggedTime
@@ -602,7 +598,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
public void plug(long batteryUptime, long batteryRealtime) {
public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
if (DEBUG && mType < 0) {
Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
+ " old mTotalTime=" + mTotalTime);
@@ -731,7 +727,7 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mTrackingReportedValues;
/*
* A sequnce counter, incremented once for each update of the stats.
* A sequence counter, incremented once for each update of the stats.
*/
int mUpdateVersion;
@@ -786,8 +782,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mCurrentReportedTotalTime = totalTime;
}
public void unplug(long batteryUptime, long batteryRealtime) {
super.unplug(batteryUptime, batteryRealtime);
public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
super.unplug(elapsedRealtime, batteryUptime, batteryRealtime);
if (mTrackingReportedValues) {
mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
mUnpluggedReportedCount = mCurrentReportedCount;
@@ -795,8 +791,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mInDischarge = true;
}
public void plug(long batteryUptime, long batteryRealtime) {
super.plug(batteryUptime, batteryRealtime);
public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
super.plug(elapsedRealtime, batteryUptime, batteryRealtime);
mInDischarge = false;
}
@@ -848,6 +844,141 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
/**
* A timer that increments in batches. It does not run for durations, but just jumps
* for a pre-determined amount.
*/
public static final class BatchTimer extends Timer {
final Uid mUid;
/**
* The last time at which we updated the timer. This is in elapsed realtime microseconds.
*/
long mLastAddedTime;
/**
* The last duration that we added to the timer. This is in microseconds.
*/
long mLastAddedDuration;
/**
* Whether we are currently in a discharge cycle.
*/
boolean mInDischarge;
BatchTimer(Uid uid, int type, ArrayList<Unpluggable> unpluggables,
boolean inDischarge, Parcel in) {
super(type, unpluggables, in);
mUid = uid;
mLastAddedTime = in.readLong();
mLastAddedDuration = in.readLong();
mInDischarge = inDischarge;
}
BatchTimer(Uid uid, int type, ArrayList<Unpluggable> unpluggables,
boolean inDischarge) {
super(type, unpluggables);
mUid = uid;
mInDischarge = inDischarge;
}
@Override
public void writeToParcel(Parcel out, long batteryRealtime) {
super.writeToParcel(out, batteryRealtime);
out.writeLong(mLastAddedTime);
out.writeLong(mLastAddedDuration);
}
@Override
public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
recomputeLastDuration(SystemClock.elapsedRealtime() * 1000, false);
mInDischarge = false;
super.plug(elapsedRealtime, batteryUptime, batteryRealtime);
}
@Override
public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
recomputeLastDuration(elapsedRealtime, false);
mInDischarge = true;
// If we are still within the last added duration, then re-added whatever remains.
if (mLastAddedTime == elapsedRealtime) {
mTotalTime += mLastAddedDuration;
}
super.unplug(elapsedRealtime, batteryUptime, batteryRealtime);
}
@Override
public void logState(Printer pw, String prefix) {
super.logState(pw, prefix);
pw.println(prefix + "mLastAddedTime=" + mLastAddedTime
+ " mLastAddedDuration=" + mLastAddedDuration);
}
private long computeOverage(long curTime) {
if (mLastAddedTime > 0) {
return mLastTime + mLastAddedDuration - curTime;
}
return 0;
}
private void recomputeLastDuration(long curTime, boolean abort) {
final long overage = computeOverage(curTime);
if (overage > 0) {
// Aborting before the duration ran out -- roll back the remaining
// duration. Only do this if currently discharging; otherwise we didn't
// actually add the time.
if (mInDischarge) {
mTotalTime -= overage;
}
if (abort) {
mLastAddedTime = 0;
} else {
mLastAddedTime = curTime;
mLastAddedDuration -= overage;
}
}
}
public void addDuration(BatteryStatsImpl stats, long durationMillis) {
final long now = SystemClock.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
mLastAddedTime = now;
mLastAddedDuration = durationMillis * 1000;
if (mInDischarge) {
mTotalTime += mLastAddedDuration;
mCount++;
}
}
public void abortLastDuration(BatteryStatsImpl stats) {
final long now = SystemClock.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
}
@Override
protected int computeCurrentCountLocked() {
return mCount;
}
@Override
protected long computeRunTimeLocked(long curBatteryRealtime) {
final long overage = computeOverage(SystemClock.elapsedRealtime() * 1000);
if (overage > 0) {
return mTotalTime = overage;
}
return mTotalTime;
}
@Override
boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
final long now = SystemClock.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
boolean stillActive = mLastAddedTime == now;
super.reset(stats, !stillActive && detachIfReset);
return !stillActive;
}
}
/**
* State for keeping track of timing information.
*/
@@ -902,12 +1033,12 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(mUpdateTime);
}
public void plug(long batteryUptime, long batteryRealtime) {
public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
if (mNesting > 0) {
if (DEBUG && mType < 0) {
Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
}
super.plug(batteryUptime, batteryRealtime);
super.plug(elapsedRealtime, batteryUptime, batteryRealtime);
mUpdateTime = batteryRealtime;
if (DEBUG && mType < 0) {
Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
@@ -1443,7 +1574,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mHistoryOverflow = false;
}
public void doUnplugLocked(long batteryUptime, long batteryRealtime) {
public void doUnplugLocked(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
NetworkStats.Entry entry = null;
// Track UID data usage
@@ -1462,7 +1593,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
mUnpluggables.get(i).unplug(elapsedRealtime, batteryUptime, batteryRealtime);
}
// Track both mobile and total overall data
@@ -1483,7 +1614,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mBluetoothPingCount = 0;
}
public void doPlugLocked(long batteryUptime, long batteryRealtime) {
public void doPlugLocked(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
NetworkStats.Entry entry = null;
for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
@@ -1498,7 +1629,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
mUnpluggables.get(i).plug(elapsedRealtime, batteryUptime, batteryRealtime);
}
// Track both mobile and total overall data
@@ -2109,6 +2240,14 @@ public final class BatteryStatsImpl extends BatteryStats {
getUidStatsLocked(uid).noteVideoTurnedOffLocked();
}
public void noteVibratorOnLocked(int uid, long durationMillis) {
getUidStatsLocked(uid).noteVibratorOnLocked(durationMillis);
}
public void noteVibratorOffLocked(int uid) {
getUidStatsLocked(uid).noteVibratorOffLocked();
}
public void noteWifiRunningLocked(WorkSource ws) {
if (!mGlobalWifiRunning) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
@@ -2402,6 +2541,8 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mVideoTurnedOn;
StopwatchTimer mVideoTurnedOnTimer;
BatchTimer mVibratorOnTimer;
Counter[] mUserActivityCounters;
/**
@@ -2439,10 +2580,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiScanTimers, mUnpluggables);
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mUnpluggables);
mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
null, mUnpluggables);
mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
null, mUnpluggables);
}
@Override
@@ -2587,15 +2724,19 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
public StopwatchTimer createAudioTurnedOnTimerLocked() {
if (mAudioTurnedOnTimer == null) {
mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
null, mUnpluggables);
}
return mAudioTurnedOnTimer;
}
@Override
public void noteAudioTurnedOnLocked() {
if (!mAudioTurnedOn) {
mAudioTurnedOn = true;
if (mAudioTurnedOnTimer == null) {
mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
null, mUnpluggables);
}
mAudioTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
createAudioTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
}
}
@@ -2603,19 +2744,25 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteAudioTurnedOffLocked() {
if (mAudioTurnedOn) {
mAudioTurnedOn = false;
mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
if (mAudioTurnedOnTimer != null) {
mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
}
public StopwatchTimer createVideoTurnedOnTimerLocked() {
if (mVideoTurnedOnTimer == null) {
mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
null, mUnpluggables);
}
return mVideoTurnedOnTimer;
}
@Override
public void noteVideoTurnedOnLocked() {
if (!mVideoTurnedOn) {
mVideoTurnedOn = true;
if (mVideoTurnedOnTimer == null) {
mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
null, mUnpluggables);
}
mVideoTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
createVideoTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
}
}
@@ -2623,7 +2770,27 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteVideoTurnedOffLocked() {
if (mVideoTurnedOn) {
mVideoTurnedOn = false;
mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
if (mVideoTurnedOnTimer != null) {
mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
}
public BatchTimer createVibratorOnTimerLocked() {
if (mVibratorOnTimer == null) {
mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal);
}
return mVibratorOnTimer;
}
public void noteVibratorOnLocked(long durationMillis) {
createVibratorOnTimerLocked().addDuration(BatteryStatsImpl.this, durationMillis);
}
public void noteVibratorOffLocked() {
if (mVibratorOnTimer != null) {
mVibratorOnTimer.abortLastDuration(BatteryStatsImpl.this);
}
}
@@ -2676,6 +2843,11 @@ public final class BatteryStatsImpl extends BatteryStats {
return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override
public Timer getVibratorOnTimer() {
return mVibratorOnTimer;
}
@Override
public void noteUserActivityLocked(int type) {
if (mUserActivityCounters == null) {
@@ -2747,6 +2919,14 @@ public final class BatteryStatsImpl extends BatteryStats {
active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
active |= mVideoTurnedOn;
}
if (mVibratorOnTimer != null) {
if (mVibratorOnTimer.reset(BatteryStatsImpl.this, false)) {
mVibratorOnTimer.detach();
mVibratorOnTimer = null;
} else {
active = true;
}
}
mLoadedTcpBytesReceived = mLoadedTcpBytesSent = 0;
mCurrentTcpBytesReceived = mCurrentTcpBytesSent = 0;
@@ -2832,9 +3012,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
if (mAudioTurnedOnTimer != null) {
mAudioTurnedOnTimer.detach();
mAudioTurnedOnTimer = null;
}
if (mVideoTurnedOnTimer != null) {
mVideoTurnedOnTimer.detach();
mVideoTurnedOnTimer = null;
}
if (mUserActivityCounters != null) {
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
@@ -2917,6 +3099,12 @@ public final class BatteryStatsImpl extends BatteryStats {
} else {
out.writeInt(0);
}
if (mVibratorOnTimer != null) {
out.writeInt(1);
mVibratorOnTimer.writeToParcel(out, batteryRealtime);
} else {
out.writeInt(0);
}
if (mUserActivityCounters != null) {
out.writeInt(1);
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
@@ -3015,6 +3203,12 @@ public final class BatteryStatsImpl extends BatteryStats {
} else {
mVideoTurnedOnTimer = null;
}
if (in.readInt() != 0) {
mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal, in);
} else {
mVibratorOnTimer = null;
}
if (in.readInt() != 0) {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
@@ -3256,14 +3450,14 @@ public final class BatteryStatsImpl extends BatteryStats {
mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
}
public void unplug(long batteryUptime, long batteryRealtime) {
public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
mUnpluggedUserTime = mUserTime;
mUnpluggedSystemTime = mSystemTime;
mUnpluggedStarts = mStarts;
mUnpluggedForegroundTime = mForegroundTime;
}
public void plug(long batteryUptime, long batteryRealtime) {
public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
}
void detach() {
@@ -3550,11 +3744,11 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggables.add(this);
}
public void unplug(long batteryUptime, long batteryRealtime) {
public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
mUnpluggedWakeups = mWakeups;
}
public void plug(long batteryUptime, long batteryRealtime) {
public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
}
void detach() {
@@ -3712,13 +3906,13 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggables.add(this);
}
public void unplug(long batteryUptime, long batteryRealtime) {
public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
mUnpluggedStarts = mStarts;
mUnpluggedLaunches = mLaunches;
}
public void plug(long batteryUptime, long batteryRealtime) {
public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
}
void detach() {
@@ -4367,7 +4561,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
mDischargeAmountScreenOn = 0;
mDischargeAmountScreenOff = 0;
doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
doUnplugLocked(realtime, mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
} else {
updateKernelWakelocksLocked();
mHistoryCur.batteryLevel = (byte)level;
@@ -4383,7 +4577,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
}
updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
doPlugLocked(realtime, getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
}
if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
if (mFile != null) {
@@ -5161,11 +5355,14 @@ public final class BatteryStatsImpl extends BatteryStats {
}
u.mAudioTurnedOn = false;
if (in.readInt() != 0) {
u.mAudioTurnedOnTimer.readSummaryFromParcelLocked(in);
u.createAudioTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
}
u.mVideoTurnedOn = false;
if (in.readInt() != 0) {
u.mVideoTurnedOnTimer.readSummaryFromParcelLocked(in);
u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
u.createVibratorOnTimerLocked().readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
@@ -5367,6 +5564,12 @@ public final class BatteryStatsImpl extends BatteryStats {
} else {
out.writeInt(0);
}
if (u.mVibratorOnTimer != null) {
out.writeInt(1);
u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
if (u.mUserActivityCounters == null) {
out.writeInt(0);

View File

@@ -1327,21 +1327,6 @@
android:label="@string/permlab_writeGservices"
android:description="@string/permdesc_writeGservices" />
<!-- @hide Change the screen compatibility mode of applications -->
<permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature"
android:label="@string/permlab_setScreenCompatibility"
android:description="@string/permdesc_setScreenCompatibility" />
<!-- Allows an application to modify the current configuration, such
as locale. -->
<permission android:name="android.permission.CHANGE_CONFIGURATION"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="system|signature"
android:label="@string/permlab_changeConfiguration"
android:description="@string/permdesc_changeConfiguration" />
<!-- Allows an application to call
{@link android.app.ActivityManager#forceStopPackage}.
@hide -->
@@ -1621,6 +1606,13 @@
android:description="@string/permdesc_updateBatteryStats"
android:protectionLevel="signature|system" />
<!-- Allows an application to update application operation statistics. Not for
use by third party apps. @hide -->
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
android:label="@string/permlab_updateAppOpsStats"
android:description="@string/permdesc_updateAppOpsStats"
android:protectionLevel="signature|system" />
<!-- Allows an application to open windows that are for use by parts
of the system user interface. Not for use by third party apps. -->
<permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"

View File

@@ -842,6 +842,12 @@
<string name="permdesc_updateBatteryStats">Allows the app to modify
collected battery statistics. Not for use by normal apps.</string>
<!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_updateAppOpsStats">modify app ops statistics</string>
<!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_updateAppOpsStats">Allows the app to modify
collected application operation statistics. Not for use by normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_backup">control system backup and restore</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->

View File

@@ -47,7 +47,7 @@ interface ILocationManager
Location getLastLocation(in LocationRequest request, String packageName);
boolean addGpsStatusListener(IGpsStatusListener listener);
boolean addGpsStatusListener(IGpsStatusListener listener, String packageName);
void removeGpsStatusListener(IGpsStatusListener listener);
boolean geocoderIsPresent();

View File

@@ -1461,7 +1461,7 @@ public class LocationManager {
}
try {
GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
result = mService.addGpsStatusListener(transport);
result = mService.addGpsStatusListener(transport, mContext.getPackageName());
if (result) {
mGpsStatusListeners.put(listener, transport);
}
@@ -1507,7 +1507,7 @@ public class LocationManager {
}
try {
GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
result = mService.addGpsStatusListener(transport);
result = mService.addGpsStatusListener(transport, mContext.getPackageName());
if (result) {
mNmeaListeners.put(listener, transport);
}

View File

@@ -0,0 +1,260 @@
/*
* Copyright (C) 2012 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.server;
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Environment;
import android.os.Process;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import com.android.internal.app.IAppOpsService;
public class AppOpsService extends IAppOpsService.Stub {
static final String TAG = "AppOps";
Context mContext;
final AtomicFile mFile;
final SparseArray<HashMap<String, Ops>> mUidOps
= new SparseArray<HashMap<String, Ops>>();
final static class Ops extends SparseArray<Op> {
public final String packageName;
public Ops(String _packageName) {
packageName = _packageName;
}
}
final static class Op {
public final int op;
public int duration;
public long time;
public Op(int _op) {
op = _op;
}
}
public AppOpsService() {
mFile = new AtomicFile(new File(Environment.getSecureDataDirectory(), "appops.xml"));
}
public void publish(Context context) {
mContext = context;
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
}
public void shutdown() {
Slog.w(TAG, "Writing app ops before shutdown...");
}
@Override
public int noteOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
Op op = getOpLocked(code, uid, packageName);
if (op == null) {
return AppOpsManager.MODE_IGNORED;
}
if (op.duration == -1) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration);
}
op.time = System.currentTimeMillis();
op.duration = 0;
}
return AppOpsManager.MODE_ALLOWED;
}
@Override
public int startOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
Op op = getOpLocked(code, uid, packageName);
if (op == null) {
return AppOpsManager.MODE_IGNORED;
}
if (op.duration == -1) {
Slog.w(TAG, "Starting op not finished: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration);
}
op.time = System.currentTimeMillis();
op.duration = -1;
}
return AppOpsManager.MODE_ALLOWED;
}
@Override
public void finishOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
Op op = getOpLocked(code, uid, packageName);
if (op == null) {
return;
}
if (op.duration != -1) {
Slog.w(TAG, "Ignoring finishing op not started: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration);
return;
}
op.duration = (int)(System.currentTimeMillis() - op.time);
}
}
@Override
public int noteTimedOperation(int code, int uid, String packageName, int duration) {
uid = handleIncomingUid(uid);
synchronized (this) {
Op op = getOpLocked(code, uid, packageName);
if (op == null) {
return AppOpsManager.MODE_IGNORED;
}
if (op.duration == -1) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration);
}
op.time = System.currentTimeMillis();
op.duration = duration;
}
return AppOpsManager.MODE_ALLOWED;
}
@Override
public void earlyFinishOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
Op op = getOpLocked(code, uid, packageName);
if (op == null) {
return;
}
if (op.duration != -1) {
Slog.w(TAG, "Noting timed op not finished: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration);
}
int newDuration = (int)(System.currentTimeMillis() - op.time);
if (newDuration < op.duration) {
op.duration = newDuration;
}
}
}
private int handleIncomingUid(int uid) {
if (uid == Binder.getCallingUid()) {
return uid;
}
if (Binder.getCallingPid() == Process.myPid()) {
return uid;
}
mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
return uid;
}
private Op getOpLocked(int code, int uid, String packageName) {
HashMap<String, Ops> pkgOps = mUidOps.get(uid);
if (pkgOps == null) {
pkgOps = new HashMap<String, Ops>();
mUidOps.put(uid, pkgOps);
}
Ops ops = pkgOps.get(packageName);
if (ops == null) {
// This is the first time we have seen this package name under this uid,
// so let's make sure it is valid.
// XXX for now we always allow null through until we can fix everything
// to provide the name.
if (packageName != null) {
final long ident = Binder.clearCallingIdentity();
try {
int pkgUid = -1;
try {
pkgUid = mContext.getPackageManager().getPackageUid(packageName,
UserHandle.getUserId(uid));
} catch (NameNotFoundException e) {
}
if (pkgUid != uid) {
// Oops! The package name is not valid for the uid they are calling
// under. Abort.
Slog.w(TAG, "Bad call: specified package " + packageName
+ " under uid " + uid + " but it is really " + pkgUid);
return null;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
ops = new Ops(packageName);
pkgOps.put(packageName, ops);
}
Op op = ops.get(code);
if (op == null) {
op = new Op(code);
ops.put(code, op);
}
return op;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump ApOps service from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
}
synchronized (this) {
pw.println("Current AppOps Service state:");
for (int i=0; i<mUidOps.size(); i++) {
pw.print(" Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":");
HashMap<String, Ops> pkgOps = mUidOps.valueAt(i);
for (Ops ops : pkgOps.values()) {
pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
for (int j=0; j<ops.size(); j++) {
Op op = ops.valueAt(j);
pw.print(" "); pw.print(AppOpsManager.opToString(op.op));
pw.print(": time=");
TimeUtils.formatDuration(System.currentTimeMillis()-op.time, pw);
pw.print(" ago");
if (op.duration == -1) {
pw.println(" (running)");
} else {
pw.print("; duration=");
TimeUtils.formatDuration(op.duration, pw);
pw.println();
}
}
}
}
}
}
}

View File

@@ -16,6 +16,7 @@
package com.android.server;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -53,6 +54,7 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -60,6 +62,7 @@ import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -124,6 +127,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
private final Context mContext;
private final AppOpsManager mAppOps;
// used internally for synchronization
private final Object mLock = new Object();
@@ -187,6 +191,7 @@ public class LocationManagerService extends ILocationManager.Stub {
public LocationManagerService(Context context) {
super();
mContext = context;
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
if (D) Log.d(TAG, "Constructed");
@@ -524,6 +529,10 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public boolean callLocationChangedLocked(Location location) {
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_LOCATION, mUid, mPackageName)
!= AppOpsManager.MODE_ALLOWED) {
return true;
}
if (mListener != null) {
try {
synchronized (this) {
@@ -1162,7 +1171,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
int pid, int uid, String packageName) {
if (intent == null && listener == null) {
throw new IllegalArgumentException("need eiter listener or intent");
throw new IllegalArgumentException("need either listener or intent");
} else if (intent != null && listener != null) {
throw new IllegalArgumentException("cannot register both listener and intent");
} else if (intent != null) {
@@ -1185,11 +1194,14 @@ public class LocationManagerService extends ILocationManager.Stub {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
// providers may use public location API's, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
// We don't check for MODE_IGNORED here; we will do that when we go to deliver
// a location.
mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName);
Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
synchronized (mLock) {
requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
}
@@ -1296,8 +1308,14 @@ public class LocationManagerService extends ILocationManager.Stub {
request.getProvider());
// no need to sanitize this request, as only the provider name is used
long identity = Binder.clearCallingIdentity();
final int uid = Binder.getCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
if (mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName)
!= AppOpsManager.MODE_ALLOWED) {
return null;
}
if (mBlacklist.isBlacklisted(packageName)) {
if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
packageName);
@@ -1381,13 +1399,24 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean addGpsStatusListener(IGpsStatusListener listener) {
public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
if (mGpsStatusProvider == null) {
return false;
}
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
LocationManager.GPS_PROVIDER);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
if (mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName)
!= AppOpsManager.MODE_ALLOWED) {
return false;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
try {
mGpsStatusProvider.addGpsStatusListener(listener);
} catch (RemoteException e) {

View File

@@ -261,7 +261,6 @@ class ServerThread extends Thread {
ServiceManager.addService(Context.USER_SERVICE,
UserManagerService.getInstance());
mContentResolver = context.getContentResolver();
// The AccountManager must come before the ContentService

View File

@@ -16,6 +16,7 @@
package com.android.server;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -30,6 +31,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Binder;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.Vibrator;
@@ -39,6 +41,9 @@ import android.provider.Settings.SettingNotFoundException;
import android.util.Slog;
import android.view.InputDevice;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
@@ -54,6 +59,8 @@ public class VibratorService extends IVibratorService.Stub
private final Context mContext;
private final PowerManager.WakeLock mWakeLock;
private final IAppOpsService mAppOpsService;
private final IBatteryStats mBatteryStatsService;
private InputManager mIm;
volatile VibrateThread mThread;
@@ -64,6 +71,8 @@ public class VibratorService extends IVibratorService.Stub
private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
private int mCurVibUid = -1;
native static boolean vibratorExists();
native static void vibratorOn(long milliseconds);
native static void vibratorOff();
@@ -75,23 +84,25 @@ public class VibratorService extends IVibratorService.Stub
private final long[] mPattern;
private final int mRepeat;
private final int mUid;
private final String mPackageName;
Vibration(IBinder token, long millis, int uid) {
this(token, millis, null, 0, uid);
Vibration(IBinder token, long millis, int uid, String packageName) {
this(token, millis, null, 0, uid, packageName);
}
Vibration(IBinder token, long[] pattern, int repeat, int uid) {
this(token, 0, pattern, repeat, uid);
Vibration(IBinder token, long[] pattern, int repeat, int uid, String packageName) {
this(token, 0, pattern, repeat, uid, packageName);
}
private Vibration(IBinder token, long millis, long[] pattern,
int repeat, int uid) {
int repeat, int uid, String packageName) {
mToken = token;
mTimeout = millis;
mStartTime = SystemClock.uptimeMillis();
mPattern = pattern;
mRepeat = repeat;
mUid = uid;
mPackageName = packageName;
}
public void binderDied() {
@@ -131,6 +142,9 @@ public class VibratorService extends IVibratorService.Stub
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
mWakeLock.setReferenceCounted(true);
mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
mVibrations = new LinkedList<Vibration>();
IntentFilter filter = new IntentFilter();
@@ -164,7 +178,7 @@ public class VibratorService extends IVibratorService.Stub
return doVibratorExists();
}
public void vibrate(long milliseconds, IBinder token) {
public void vibrate(String packageName, long milliseconds, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
@@ -180,12 +194,18 @@ public class VibratorService extends IVibratorService.Stub
return;
}
Vibration vib = new Vibration(token, milliseconds, uid);
synchronized (mVibrations) {
removeVibrationLocked(token);
doCancelVibrateLocked();
mCurrentVibration = vib;
startVibrationLocked(vib);
Vibration vib = new Vibration(token, milliseconds, uid, packageName);
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mVibrations) {
removeVibrationLocked(token);
doCancelVibrateLocked();
mCurrentVibration = vib;
startVibrationLocked(vib);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@@ -199,7 +219,7 @@ public class VibratorService extends IVibratorService.Stub
return true;
}
public void vibratePattern(long[] pattern, int repeat, IBinder token) {
public void vibratePattern(String packageName, long[] pattern, int repeat, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
@@ -224,7 +244,7 @@ public class VibratorService extends IVibratorService.Stub
return;
}
Vibration vib = new Vibration(token, pattern, repeat, uid);
Vibration vib = new Vibration(token, pattern, repeat, uid, packageName);
try {
token.linkToDeath(vib, 0);
} catch (RemoteException e) {
@@ -291,11 +311,13 @@ public class VibratorService extends IVibratorService.Stub
}
doVibratorOff();
mH.removeCallbacks(mVibrationRunnable);
reportFinishVibrationLocked();
}
// Lock held on mVibrations
private void startNextVibrationLocked() {
if (mVibrations.size() <= 0) {
reportFinishVibrationLocked();
mCurrentVibration = null;
return;
}
@@ -305,8 +327,19 @@ public class VibratorService extends IVibratorService.Stub
// Lock held on mVibrations
private void startVibrationLocked(final Vibration vib) {
try {
int mode = mAppOpsService.startOperation(AppOpsManager.OP_VIBRATE, vib.mUid, vib.mPackageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
if (mode == AppOpsManager.MODE_ERRORED) {
Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
}
mH.post(mVibrationRunnable);
return;
}
} catch (RemoteException e) {
}
if (vib.mTimeout != 0) {
doVibratorOn(vib.mTimeout);
doVibratorOn(vib.mTimeout, vib.mUid);
mH.postDelayed(mVibrationRunnable, vib.mTimeout);
} else {
// mThread better be null here. doCancelVibrate should always be
@@ -316,6 +349,17 @@ public class VibratorService extends IVibratorService.Stub
}
}
private void reportFinishVibrationLocked() {
if (mCurrentVibration != null) {
try {
mAppOpsService.finishOperation(AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
mCurrentVibration.mPackageName);
} catch (RemoteException e) {
}
mCurrentVibration = null;
}
}
// Lock held on mVibrations
private Vibration removeVibrationLocked(IBinder token) {
ListIterator<Vibration> iter = mVibrations.listIterator(0);
@@ -413,8 +457,13 @@ public class VibratorService extends IVibratorService.Stub
return vibratorExists();
}
private void doVibratorOn(long millis) {
private void doVibratorOn(long millis, int uid) {
synchronized (mInputDeviceVibrators) {
try {
mBatteryStatsService.noteVibratorOn(uid, millis);
mCurVibUid = uid;
} catch (RemoteException e) {
}
final int vibratorCount = mInputDeviceVibrators.size();
if (vibratorCount != 0) {
for (int i = 0; i < vibratorCount; i++) {
@@ -428,6 +477,13 @@ public class VibratorService extends IVibratorService.Stub
private void doVibratorOff() {
synchronized (mInputDeviceVibrators) {
if (mCurVibUid >= 0) {
try {
mBatteryStatsService.noteVibratorOff(mCurVibUid);
} catch (RemoteException e) {
}
mCurVibUid = -1;
}
final int vibratorCount = mInputDeviceVibrators.size();
if (vibratorCount != 0) {
for (int i = 0; i < vibratorCount; i++) {
@@ -470,10 +526,11 @@ public class VibratorService extends IVibratorService.Stub
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
synchronized (this) {
final long[] pattern = mVibration.mPattern;
final int len = pattern.length;
final int repeat = mVibration.mRepeat;
final int uid = mVibration.mUid;
int index = 0;
long[] pattern = mVibration.mPattern;
int len = pattern.length;
int repeat = mVibration.mRepeat;
long duration = 0;
while (!mDone) {
@@ -493,7 +550,7 @@ public class VibratorService extends IVibratorService.Stub
// duration is saved for delay() at top of loop
duration = pattern[index++];
if (duration > 0) {
VibratorService.this.doVibratorOn(duration);
VibratorService.this.doVibratorOn(duration, uid);
}
} else {
if (repeat < 0) {

View File

@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import com.android.internal.R;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessStats;
import com.android.server.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
@@ -619,9 +620,14 @@ public final class ActivityManagerService extends ActivityManagerNative
final BatteryStatsService mBatteryStatsService;
/**
* information about component usage
* Information about component usage
*/
final UsageStatsService mUsageStatsService;
/**
* Information about and control over application operations
*/
final AppOpsService mAppOpsService;
/**
* Current configuration information. HistoryRecord objects are given
@@ -1450,7 +1456,8 @@ public final class ActivityManagerService extends ActivityManagerNative
m.mBatteryStatsService.publish(context);
m.mUsageStatsService.publish(context);
m.mAppOpsService.publish(context);
synchronized (thr) {
thr.mReady = true;
thr.notifyAll();
@@ -1613,9 +1620,10 @@ public final class ActivityManagerService extends ActivityManagerNative
mOnBattery = DEBUG_POWER ? true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
mUsageStatsService = new UsageStatsService(new File(
systemDir, "usagestats").toString());
mAppOpsService = new AppOpsService();
mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
// User 0 is the first and only user that runs at boot.
@@ -7174,7 +7182,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
mAppOpsService.shutdown();
mUsageStatsService.shutdown();
mBatteryStatsService.shutdown();

View File

@@ -144,6 +144,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
}
public void noteVibratorOn(int uid, long durationMillis) {
enforceCallingPermission();
synchronized (mStats) {
mStats.noteVibratorOnLocked(uid, durationMillis);
}
}
public void noteVibratorOff(int uid) {
enforceCallingPermission();
synchronized (mStats) {
mStats.noteVibratorOffLocked(uid);
}
}
public void noteStartGps(int uid) {
enforceCallingPermission();
synchronized (mStats) {

View File

@@ -17,6 +17,7 @@
package com.android.server.location;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -56,6 +57,8 @@ import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import android.util.NtpTrustedTime;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.ProviderProperties;
@@ -305,6 +308,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
private final PendingIntent mWakeupIntent;
private final PendingIntent mTimeoutIntent;
private final IAppOpsService mAppOpsService;
private final IBatteryStats mBatteryStats;
// only modified on handler thread
@@ -434,6 +438,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
// App ops service to keep track of who is accessing the GPS
mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
Context.APP_OPS_SERVICE));
// Battery statistics service to be notified when GPS turns on or off
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
@@ -863,6 +871,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
if (newUid) {
try {
mAppOpsService.startOperation(AppOpsManager.OP_GPS, uid1, null);
mBatteryStats.noteStartGps(uid1);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException", e);
@@ -882,6 +891,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
if (oldUid) {
try {
mBatteryStats.noteStopGps(uid1);
mAppOpsService.finishOperation(AppOpsManager.OP_GPS, uid1, null);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException", e);
}

View File

@@ -81,6 +81,13 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
/** @hide */
@Override
public int getPackageUid(String packageName, int userHandle)
throws NameNotFoundException {
throw new UnsupportedOperationException();
}
@Override
public PermissionInfo getPermissionInfo(String name, int flags)
throws NameNotFoundException {