summaryrefslogtreecommitdiffstats
path: root/widget/gonk/GonkPermission.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/gonk/GonkPermission.cpp')
-rw-r--r--widget/gonk/GonkPermission.cpp195
1 files changed, 195 insertions, 0 deletions
diff --git a/widget/gonk/GonkPermission.cpp b/widget/gonk/GonkPermission.cpp
new file mode 100644
index 000000000..8ebc43de8
--- /dev/null
+++ b/widget/gonk/GonkPermission.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2012 Mozilla Foundation
+ *
+ * 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 "GonkPermission.h"
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPermissionController.h>
+
+#ifndef HAVE_ANDROID_OS
+#define HAVE_ANDROID_OS 1
+#endif
+#include <private/android_filesystem_config.h>
+
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/SyncRunnable.h"
+#include "nsIAppsService.h"
+#include "mozIApplication.h"
+#include "nsThreadUtils.h"
+
+#undef LOG
+#include <android/log.h>
+#undef ALOGE
+#define ALOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "gonkperm" , ## args)
+
+using namespace android;
+using namespace mozilla;
+
+// Checking permissions needs to happen on the main thread, but the
+// binder callback is called on a special binder thread, so we use
+// this runnable for that.
+class GonkPermissionChecker : public Runnable {
+ int32_t mPid;
+ bool mCanUseCamera;
+
+ explicit GonkPermissionChecker(int32_t pid)
+ : mPid(pid)
+ , mCanUseCamera(false)
+ {
+ }
+
+public:
+ static already_AddRefed<GonkPermissionChecker> Inspect(int32_t pid)
+ {
+ RefPtr<GonkPermissionChecker> that = new GonkPermissionChecker(pid);
+ nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+ MOZ_ASSERT(mainThread);
+ SyncRunnable::DispatchToThread(mainThread, that);
+ return that.forget();
+ }
+
+ bool CanUseCamera()
+ {
+ return mCanUseCamera;
+ }
+
+ NS_IMETHOD Run();
+};
+
+NS_IMETHODIMP
+GonkPermissionChecker::Run()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // Find our ContentParent.
+ dom::ContentParent *contentParent = nullptr;
+ {
+ nsTArray<dom::ContentParent*> parents;
+ dom::ContentParent::GetAll(parents);
+ for (uint32_t i = 0; i < parents.Length(); ++i) {
+ if (parents[i]->Pid() == mPid) {
+ contentParent = parents[i];
+ break;
+ }
+ }
+ }
+ if (!contentParent) {
+ ALOGE("pid=%d denied: can't find ContentParent", mPid);
+ return NS_OK;
+ }
+
+ // Now iterate its apps...
+ const ManagedContainer<dom::PBrowserParent>& browsers =
+ contentParent->ManagedPBrowserParent();
+ for (auto iter = browsers.ConstIter(); !iter.Done(); iter.Next()) {
+ dom::TabParent *tabParent =
+ static_cast<dom::TabParent*>(iter.Get()->GetKey());
+ nsCOMPtr<mozIApplication> mozApp = tabParent->GetOwnOrContainingApp();
+ if (!mozApp) {
+ continue;
+ }
+
+ // ...and check if any of them has camera access.
+ bool appCanUseCamera;
+ nsresult rv = mozApp->HasPermission("camera", &appCanUseCamera);
+ if (NS_SUCCEEDED(rv) && appCanUseCamera) {
+ mCanUseCamera = true;
+ return NS_OK;
+ }
+ }
+ return NS_OK;
+}
+
+bool
+GonkPermissionService::checkPermission(const String16& permission, int32_t pid,
+ int32_t uid)
+{
+ // root can do anything.
+ if (0 == uid) {
+ return true;
+ }
+
+ String8 perm8(permission);
+
+ // Some ril implementations need android.permission.MODIFY_AUDIO_SETTINGS
+ if ((uid == AID_SYSTEM || uid == AID_RADIO || uid == AID_BLUETOOTH) &&
+ perm8 == "android.permission.MODIFY_AUDIO_SETTINGS") {
+ return true;
+ }
+
+ // No other permissions apply to non-app processes.
+ if (uid < AID_APP) {
+ ALOGE("%s for pid=%d,uid=%d denied: not an app",
+ String8(permission).string(), pid, uid);
+ return false;
+ }
+
+ // Only these permissions can be granted to apps through this service.
+ if (perm8 != "android.permission.CAMERA" &&
+ perm8 != "android.permission.RECORD_AUDIO") {
+ ALOGE("%s for pid=%d,uid=%d denied: unsupported permission",
+ String8(permission).string(), pid, uid);
+ return false;
+ }
+
+ // Users granted the permission through a prompt dialog.
+ // Before permission managment of gUM is done, app cannot remember the
+ // permission.
+ PermissionGrant permGrant(perm8.string(), pid);
+ if (nsTArray<PermissionGrant>::NoIndex != mGrantArray.IndexOf(permGrant)) {
+ mGrantArray.RemoveElement(permGrant);
+ return true;
+ }
+
+ // Camera/audio record permissions are allowed for apps with the
+ // "camera" permission.
+ RefPtr<GonkPermissionChecker> checker =
+ GonkPermissionChecker::Inspect(pid);
+ bool canUseCamera = checker->CanUseCamera();
+ if (!canUseCamera) {
+ ALOGE("%s for pid=%d,uid=%d denied: not granted by user or app manifest",
+ String8(permission).string(), pid, uid);
+ }
+ return canUseCamera;
+}
+
+static GonkPermissionService* gGonkPermissionService = NULL;
+
+/* static */
+void
+GonkPermissionService::instantiate()
+{
+ defaultServiceManager()->addService(String16(getServiceName()),
+ GetInstance());
+}
+
+/* static */
+GonkPermissionService*
+GonkPermissionService::GetInstance()
+{
+ if (!gGonkPermissionService) {
+ gGonkPermissionService = new GonkPermissionService();
+ }
+ return gGonkPermissionService;
+}
+
+void
+GonkPermissionService::addGrantInfo(const char* permission, int32_t pid)
+{
+ mGrantArray.AppendElement(PermissionGrant(permission, pid));
+}