michael@0: /* michael@0: * Copyright (C) 2012 Mozilla Foundation michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include "GonkPermission.h" michael@0: michael@0: #include "mozilla/dom/ContentParent.h" michael@0: #include "mozilla/dom/TabParent.h" michael@0: #include "mozilla/SyncRunnable.h" michael@0: #include "nsIAppsService.h" michael@0: #include "mozIApplication.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: #undef LOG michael@0: #include michael@0: #define ALOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "gonkperm" , ## args) michael@0: michael@0: using namespace android; michael@0: using namespace mozilla; michael@0: michael@0: // Checking permissions needs to happen on the main thread, but the michael@0: // binder callback is called on a special binder thread, so we use michael@0: // this runnable for that. michael@0: class GonkPermissionChecker : public nsRunnable { michael@0: int32_t mPid; michael@0: bool mCanUseCamera; michael@0: michael@0: explicit GonkPermissionChecker(int32_t pid) michael@0: : mPid(pid) michael@0: , mCanUseCamera(false) michael@0: { michael@0: } michael@0: michael@0: public: michael@0: static already_AddRefed Inspect(int32_t pid) michael@0: { michael@0: nsRefPtr that = new GonkPermissionChecker(pid); michael@0: nsCOMPtr mainThread = do_GetMainThread(); michael@0: MOZ_ASSERT(mainThread); michael@0: SyncRunnable::DispatchToThread(mainThread, that); michael@0: return that.forget(); michael@0: } michael@0: michael@0: bool CanUseCamera() michael@0: { michael@0: return mCanUseCamera; michael@0: } michael@0: michael@0: NS_IMETHOD Run(); michael@0: }; michael@0: michael@0: NS_IMETHODIMP michael@0: GonkPermissionChecker::Run() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: // Find our ContentParent. michael@0: dom::ContentParent *contentParent = nullptr; michael@0: { michael@0: nsTArray parents; michael@0: dom::ContentParent::GetAll(parents); michael@0: for (uint32_t i = 0; i < parents.Length(); ++i) { michael@0: if (parents[i]->Pid() == mPid) { michael@0: contentParent = parents[i]; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: if (!contentParent) { michael@0: ALOGE("pid=%d denied: can't find ContentParent", mPid); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Now iterate its apps... michael@0: for (uint32_t i = 0; i < contentParent->ManagedPBrowserParent().Length(); i++) { michael@0: dom::TabParent *tabParent = michael@0: static_cast(contentParent->ManagedPBrowserParent()[i]); michael@0: nsCOMPtr mozApp = tabParent->GetOwnOrContainingApp(); michael@0: if (!mozApp) { michael@0: continue; michael@0: } michael@0: michael@0: // ...and check if any of them has camera access. michael@0: bool appCanUseCamera; michael@0: nsresult rv = mozApp->HasPermission("camera", &appCanUseCamera); michael@0: if (NS_SUCCEEDED(rv) && appCanUseCamera) { michael@0: mCanUseCamera = true; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: GonkPermissionService::checkPermission(const String16& permission, int32_t pid, michael@0: int32_t uid) michael@0: { michael@0: // root can do anything. michael@0: if (0 == uid) { michael@0: return true; michael@0: } michael@0: michael@0: String8 perm8(permission); michael@0: michael@0: // Some ril implementations need android.permission.MODIFY_AUDIO_SETTINGS michael@0: if (uid == AID_RADIO && michael@0: perm8 == "android.permission.MODIFY_AUDIO_SETTINGS") { michael@0: return true; michael@0: } michael@0: michael@0: // No other permissions apply to non-app processes. michael@0: if (uid < AID_APP) { michael@0: ALOGE("%s for pid=%d,uid=%d denied: not an app", michael@0: String8(permission).string(), pid, uid); michael@0: return false; michael@0: } michael@0: michael@0: // Only these permissions can be granted to apps through this service. michael@0: if (perm8 != "android.permission.CAMERA" && michael@0: perm8 != "android.permission.RECORD_AUDIO") { michael@0: ALOGE("%s for pid=%d,uid=%d denied: unsupported permission", michael@0: String8(permission).string(), pid, uid); michael@0: return false; michael@0: } michael@0: michael@0: // Users granted the permission through a prompt dialog. michael@0: // Before permission managment of gUM is done, app cannot remember the michael@0: // permission. michael@0: PermissionGrant permGrant(perm8.string(), pid); michael@0: if (nsTArray::NoIndex != mGrantArray.IndexOf(permGrant)) { michael@0: mGrantArray.RemoveElement(permGrant); michael@0: return true; michael@0: } michael@0: michael@0: // Camera/audio record permissions are allowed for apps with the michael@0: // "camera" permission. michael@0: nsRefPtr checker = michael@0: GonkPermissionChecker::Inspect(pid); michael@0: bool canUseCamera = checker->CanUseCamera(); michael@0: if (!canUseCamera) { michael@0: ALOGE("%s for pid=%d,uid=%d denied: not granted by user or app manifest", michael@0: String8(permission).string(), pid, uid); michael@0: } michael@0: return canUseCamera; michael@0: } michael@0: michael@0: static GonkPermissionService* gGonkPermissionService = NULL; michael@0: michael@0: /* static */ michael@0: void michael@0: GonkPermissionService::instantiate() michael@0: { michael@0: defaultServiceManager()->addService(String16(getServiceName()), michael@0: GetInstance()); michael@0: } michael@0: michael@0: /* static */ michael@0: GonkPermissionService* michael@0: GonkPermissionService::GetInstance() michael@0: { michael@0: if (!gGonkPermissionService) { michael@0: gGonkPermissionService = new GonkPermissionService(); michael@0: } michael@0: return gGonkPermissionService; michael@0: } michael@0: michael@0: void michael@0: GonkPermissionService::addGrantInfo(const char* permission, int32_t pid) michael@0: { michael@0: mGrantArray.AppendElement(PermissionGrant(permission, pid)); michael@0: }