diff --git a/include/binder/AppOpsManager.h b/include/binder/AppOpsManager.h new file mode 100644 index 000000000..f64d5da17 --- /dev/null +++ b/include/binder/AppOpsManager.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef ANDROID_APP_OPS_MANAGER_H +#define ANDROID_APP_OPS_MANAGER_H + +#include + +#include + +// --------------------------------------------------------------------------- +namespace android { + +class AppOpsManager +{ +public: + enum { + MODE_ALLOWED = 0, + MODE_IGNORED = 1, + MODE_ERRORED = 2 + }; + + enum { + OP_NONE = -1, + OP_COARSE_LOCATION = 0, + OP_FINE_LOCATION = 1, + OP_GPS = 2, + OP_VIBRATE = 3, + OP_READ_CONTACTS = 4, + OP_WRITE_CONTACTS = 5, + OP_READ_CALL_LOG = 6, + OP_WRITE_CALL_LOG = 7, + OP_READ_CALENDAR = 8, + OP_WRITE_CALENDAR = 9, + OP_WIFI_SCAN = 10, + OP_POST_NOTIFICATION = 11, + OP_NEIGHBORING_CELLS = 12, + OP_CALL_PHONE = 13, + OP_READ_SMS = 14, + OP_WRITE_SMS = 15, + OP_RECEIVE_SMS = 16, + OP_RECEIVE_EMERGECY_SMS = 17, + OP_RECEIVE_MMS = 18, + OP_RECEIVE_WAP_PUSH = 19, + OP_SEND_SMS = 20, + OP_READ_ICC_SMS = 21, + OP_WRITE_ICC_SMS = 22, + OP_WRITE_SETTINGS = 23, + OP_SYSTEM_ALERT_WINDOW = 24, + OP_ACCESS_NOTIFICATIONS = 25, + OP_CAMERA = 26, + OP_RECORD_AUDIO = 27, + OP_PLAY_AUDIO = 28 + }; + + AppOpsManager(); + + int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); + int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); + int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage); + void finishOp(int32_t op, int32_t uid, const String16& callingPackage); + void startWatchingMode(int32_t op, const String16& packageName, + const sp& callback); + void stopWatchingMode(const sp& callback); + +private: + Mutex mLock; + sp mService; + + sp getService(); +}; + + +}; // namespace android +// --------------------------------------------------------------------------- +#endif // ANDROID_APP_OPS_MANAGER_H diff --git a/include/binder/IAppOpsCallback.h b/include/binder/IAppOpsCallback.h new file mode 100644 index 000000000..7f8eb0168 --- /dev/null +++ b/include/binder/IAppOpsCallback.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 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. + */ + +// +#ifndef ANDROID_IAPP_OPS_CALLBACK_H +#define ANDROID_IAPP_OPS_CALLBACK_H + +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class IAppOpsCallback : public IInterface +{ +public: + DECLARE_META_INTERFACE(AppOpsCallback); + + virtual void opChanged(int32_t op, const String16& packageName) = 0; + + enum { + OP_CHANGED_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + }; +}; + +// ---------------------------------------------------------------------- + +class BnAppOpsCallback : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_IAPP_OPS_CALLBACK_H + diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h new file mode 100644 index 000000000..2883e3842 --- /dev/null +++ b/include/binder/IAppOpsService.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2013 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. + */ + +// +#ifndef ANDROID_IAPP_OPS_SERVICE_H +#define ANDROID_IAPP_OPS_SERVICE_H + +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class IAppOpsService : public IInterface +{ +public: + DECLARE_META_INTERFACE(AppOpsService); + + virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; + virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0; + virtual int32_t startOperation(int32_t code, int32_t uid, const String16& packageName) = 0; + virtual void finishOperation(int32_t code, int32_t uid, const String16& packageName) = 0; + virtual void startWatchingMode(int32_t op, const String16& packageName, + const sp& callback) = 0; + virtual void stopWatchingMode(const sp& callback) = 0; + + enum { + CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1, + START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2, + FINISH_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+3, + START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4, + STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5 + }; +}; + +// ---------------------------------------------------------------------- + +class BnAppOpsService : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_IAPP_OPS_SERVICE_H + diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index d449298db..994d3dbe3 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -14,8 +14,11 @@ # we have the common sources, plus some device-specific stuff sources := \ + AppOpsManager.cpp \ Binder.cpp \ BpBinder.cpp \ + IAppOpsCallback.cpp \ + IAppOpsService.cpp \ IInterface.cpp \ IMemory.cpp \ IPCThreadState.cpp \ diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp new file mode 100644 index 000000000..5d36dd2e0 --- /dev/null +++ b/libs/binder/AppOpsManager.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2013 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. + */ + +#include +#include + +#include + +namespace android { + +static String16 _appops("appops"); + +AppOpsManager::AppOpsManager() +{ +} + +sp AppOpsManager::getService() +{ + int64_t startTime = 0; + mLock.lock(); + sp service = mService; + while (true) { + if (service == NULL || !service->asBinder()->isBinderAlive()) { + sp binder = defaultServiceManager()->checkService(_appops); + if (binder == NULL) { + // Wait for the app ops service to come back... + if (startTime == 0) { + startTime = uptimeMillis(); + ALOGI("Waiting for app ops service"); + } else if ((uptimeMillis()-startTime) > 10000) { + ALOGW("Waiting too long for app ops service, giving up"); + return NULL; + } + sleep(1); + } else { + service = interface_cast(binder); + mService = service; + } + } + } + mLock.unlock(); + return service; +} + +int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage) +{ + sp service = getService(); + return service != NULL ? service->checkOperation(op, uid, callingPackage) : MODE_IGNORED; +} + +int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) { + sp service = getService(); + return service != NULL ? service->noteOperation(op, uid, callingPackage) : MODE_IGNORED; +} + +int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) { + sp service = getService(); + return service != NULL ? service->startOperation(op, uid, callingPackage) : MODE_IGNORED; +} + +void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) { + sp service = getService(); + if (service != NULL) { + service->finishOperation(op, uid, callingPackage); + } +} + +void AppOpsManager::startWatchingMode(int32_t op, const String16& packageName, + const sp& callback) { + sp service = getService(); + if (service != NULL) { + service->startWatchingMode(op, packageName, callback); + } +} + +void AppOpsManager::stopWatchingMode(const sp& callback) { + sp service = getService(); + if (service != NULL) { + service->stopWatchingMode(callback); + } +} + +}; // namespace android diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp new file mode 100644 index 000000000..e0aad2308 --- /dev/null +++ b/libs/binder/IAppOpsCallback.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 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. + */ + +#define LOG_TAG "AppOpsCallback" + +#include + +#include +#include +#include +#include + +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class BpAppOpsCallback : public BpInterface +{ +public: + BpAppOpsCallback(const sp& impl) + : BpInterface(impl) + { + } + + virtual void opChanged(int32_t op, const String16& packageName) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsCallback::getInterfaceDescriptor()); + data.writeInt32(op); + data.writeString16(packageName); + remote()->transact(OP_CHANGED_TRANSACTION, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallback"); + +// ---------------------------------------------------------------------- + +status_t BnAppOpsCallback::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case OP_CHANGED_TRANSACTION: { + CHECK_INTERFACE(IAppOpsCallback, data, reply); + int32_t op = data.readInt32(); + String16 packageName = data.readString16(); + opChanged(op, packageName); + reply->writeNoException(); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp new file mode 100644 index 000000000..d8922c906 --- /dev/null +++ b/libs/binder/IAppOpsService.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2013 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. + */ + +#define LOG_TAG "AppOpsService" + +#include + +#include +#include +#include +#include + +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class BpAppOpsService : public BpInterface +{ +public: + BpAppOpsService(const sp& impl) + : BpInterface(impl) + { + } + + virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(code); + data.writeInt32(uid); + data.writeString16(packageName); + remote()->transact(CHECK_OPERATION_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return 0; + return reply.readInt32() != 0; + } + + virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(code); + data.writeInt32(uid); + data.writeString16(packageName); + remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return 0; + return reply.readInt32() != 0; + } + + virtual int32_t startOperation(int32_t code, int32_t uid, const String16& packageName) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(code); + data.writeInt32(uid); + data.writeString16(packageName); + remote()->transact(START_OPERATION_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return 0; + return reply.readInt32() != 0; + } + + virtual void finishOperation(int32_t code, int32_t uid, const String16& packageName) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(code); + data.writeInt32(uid); + data.writeString16(packageName); + remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply); + } + + virtual void startWatchingMode(int32_t op, const String16& packageName, + const sp& callback) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(op); + data.writeString16(packageName); + data.writeStrongBinder(callback->asBinder()); + remote()->transact(START_WATCHING_MODE_TRANSACTION, data, &reply); + } + + virtual void stopWatchingMode(const sp& callback) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeStrongBinder(callback->asBinder()); + remote()->transact(STOP_WATCHING_MODE_TRANSACTION, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService"); + +// ---------------------------------------------------------------------- + +status_t BnAppOpsService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + //printf("AppOpsService received: "); data.print(); + switch(code) { + case CHECK_OPERATION_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + int32_t code = data.readInt32(); + int32_t uid = data.readInt32(); + String16 packageName = data.readString16(); + int32_t res = checkOperation(code, uid, packageName); + reply->writeNoException(); + reply->writeInt32(res); + return NO_ERROR; + } break; + case NOTE_OPERATION_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + int32_t code = data.readInt32(); + int32_t uid = data.readInt32(); + String16 packageName = data.readString16(); + int32_t res = noteOperation(code, uid, packageName); + reply->writeNoException(); + reply->writeInt32(res); + return NO_ERROR; + } break; + case START_OPERATION_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + int32_t code = data.readInt32(); + int32_t uid = data.readInt32(); + String16 packageName = data.readString16(); + int32_t res = startOperation(code, uid, packageName); + reply->writeNoException(); + reply->writeInt32(res); + return NO_ERROR; + } break; + case FINISH_OPERATION_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + int32_t code = data.readInt32(); + int32_t uid = data.readInt32(); + String16 packageName = data.readString16(); + finishOperation(code, uid, packageName); + reply->writeNoException(); + return NO_ERROR; + } break; + case START_WATCHING_MODE_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + int32_t op = data.readInt32(); + String16 packageName = data.readString16(); + sp callback = interface_cast(data.readStrongBinder()); + startWatchingMode(op, packageName, callback); + reply->writeNoException(); + return NO_ERROR; + } break; + case STOP_WATCHING_MODE_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + sp callback = interface_cast(data.readStrongBinder()); + stopWatchingMode(callback); + reply->writeNoException(); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android