|
1 /* |
|
2 * Copyright (C) 2012 Mozilla Foundation |
|
3 * |
|
4 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 * you may not use this file except in compliance with the License. |
|
6 * You may obtain a copy of the License at |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
10 * Unless required by applicable law or agreed to in writing, software |
|
11 * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 * See the License for the specific language governing permissions and |
|
14 * limitations under the License. |
|
15 */ |
|
16 |
|
17 #include <binder/IPCThreadState.h> |
|
18 #include <binder/ProcessState.h> |
|
19 #include <binder/IServiceManager.h> |
|
20 #include <binder/IPermissionController.h> |
|
21 #include <private/android_filesystem_config.h> |
|
22 #include "GonkPermission.h" |
|
23 |
|
24 #include "mozilla/dom/ContentParent.h" |
|
25 #include "mozilla/dom/TabParent.h" |
|
26 #include "mozilla/SyncRunnable.h" |
|
27 #include "nsIAppsService.h" |
|
28 #include "mozIApplication.h" |
|
29 #include "nsThreadUtils.h" |
|
30 |
|
31 #undef LOG |
|
32 #include <android/log.h> |
|
33 #define ALOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "gonkperm" , ## args) |
|
34 |
|
35 using namespace android; |
|
36 using namespace mozilla; |
|
37 |
|
38 // Checking permissions needs to happen on the main thread, but the |
|
39 // binder callback is called on a special binder thread, so we use |
|
40 // this runnable for that. |
|
41 class GonkPermissionChecker : public nsRunnable { |
|
42 int32_t mPid; |
|
43 bool mCanUseCamera; |
|
44 |
|
45 explicit GonkPermissionChecker(int32_t pid) |
|
46 : mPid(pid) |
|
47 , mCanUseCamera(false) |
|
48 { |
|
49 } |
|
50 |
|
51 public: |
|
52 static already_AddRefed<GonkPermissionChecker> Inspect(int32_t pid) |
|
53 { |
|
54 nsRefPtr<GonkPermissionChecker> that = new GonkPermissionChecker(pid); |
|
55 nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); |
|
56 MOZ_ASSERT(mainThread); |
|
57 SyncRunnable::DispatchToThread(mainThread, that); |
|
58 return that.forget(); |
|
59 } |
|
60 |
|
61 bool CanUseCamera() |
|
62 { |
|
63 return mCanUseCamera; |
|
64 } |
|
65 |
|
66 NS_IMETHOD Run(); |
|
67 }; |
|
68 |
|
69 NS_IMETHODIMP |
|
70 GonkPermissionChecker::Run() |
|
71 { |
|
72 MOZ_ASSERT(NS_IsMainThread()); |
|
73 |
|
74 // Find our ContentParent. |
|
75 dom::ContentParent *contentParent = nullptr; |
|
76 { |
|
77 nsTArray<dom::ContentParent*> parents; |
|
78 dom::ContentParent::GetAll(parents); |
|
79 for (uint32_t i = 0; i < parents.Length(); ++i) { |
|
80 if (parents[i]->Pid() == mPid) { |
|
81 contentParent = parents[i]; |
|
82 break; |
|
83 } |
|
84 } |
|
85 } |
|
86 if (!contentParent) { |
|
87 ALOGE("pid=%d denied: can't find ContentParent", mPid); |
|
88 return NS_OK; |
|
89 } |
|
90 |
|
91 // Now iterate its apps... |
|
92 for (uint32_t i = 0; i < contentParent->ManagedPBrowserParent().Length(); i++) { |
|
93 dom::TabParent *tabParent = |
|
94 static_cast<dom::TabParent*>(contentParent->ManagedPBrowserParent()[i]); |
|
95 nsCOMPtr<mozIApplication> mozApp = tabParent->GetOwnOrContainingApp(); |
|
96 if (!mozApp) { |
|
97 continue; |
|
98 } |
|
99 |
|
100 // ...and check if any of them has camera access. |
|
101 bool appCanUseCamera; |
|
102 nsresult rv = mozApp->HasPermission("camera", &appCanUseCamera); |
|
103 if (NS_SUCCEEDED(rv) && appCanUseCamera) { |
|
104 mCanUseCamera = true; |
|
105 return NS_OK; |
|
106 } |
|
107 } |
|
108 return NS_OK; |
|
109 } |
|
110 |
|
111 bool |
|
112 GonkPermissionService::checkPermission(const String16& permission, int32_t pid, |
|
113 int32_t uid) |
|
114 { |
|
115 // root can do anything. |
|
116 if (0 == uid) { |
|
117 return true; |
|
118 } |
|
119 |
|
120 String8 perm8(permission); |
|
121 |
|
122 // Some ril implementations need android.permission.MODIFY_AUDIO_SETTINGS |
|
123 if (uid == AID_RADIO && |
|
124 perm8 == "android.permission.MODIFY_AUDIO_SETTINGS") { |
|
125 return true; |
|
126 } |
|
127 |
|
128 // No other permissions apply to non-app processes. |
|
129 if (uid < AID_APP) { |
|
130 ALOGE("%s for pid=%d,uid=%d denied: not an app", |
|
131 String8(permission).string(), pid, uid); |
|
132 return false; |
|
133 } |
|
134 |
|
135 // Only these permissions can be granted to apps through this service. |
|
136 if (perm8 != "android.permission.CAMERA" && |
|
137 perm8 != "android.permission.RECORD_AUDIO") { |
|
138 ALOGE("%s for pid=%d,uid=%d denied: unsupported permission", |
|
139 String8(permission).string(), pid, uid); |
|
140 return false; |
|
141 } |
|
142 |
|
143 // Users granted the permission through a prompt dialog. |
|
144 // Before permission managment of gUM is done, app cannot remember the |
|
145 // permission. |
|
146 PermissionGrant permGrant(perm8.string(), pid); |
|
147 if (nsTArray<PermissionGrant>::NoIndex != mGrantArray.IndexOf(permGrant)) { |
|
148 mGrantArray.RemoveElement(permGrant); |
|
149 return true; |
|
150 } |
|
151 |
|
152 // Camera/audio record permissions are allowed for apps with the |
|
153 // "camera" permission. |
|
154 nsRefPtr<GonkPermissionChecker> checker = |
|
155 GonkPermissionChecker::Inspect(pid); |
|
156 bool canUseCamera = checker->CanUseCamera(); |
|
157 if (!canUseCamera) { |
|
158 ALOGE("%s for pid=%d,uid=%d denied: not granted by user or app manifest", |
|
159 String8(permission).string(), pid, uid); |
|
160 } |
|
161 return canUseCamera; |
|
162 } |
|
163 |
|
164 static GonkPermissionService* gGonkPermissionService = NULL; |
|
165 |
|
166 /* static */ |
|
167 void |
|
168 GonkPermissionService::instantiate() |
|
169 { |
|
170 defaultServiceManager()->addService(String16(getServiceName()), |
|
171 GetInstance()); |
|
172 } |
|
173 |
|
174 /* static */ |
|
175 GonkPermissionService* |
|
176 GonkPermissionService::GetInstance() |
|
177 { |
|
178 if (!gGonkPermissionService) { |
|
179 gGonkPermissionService = new GonkPermissionService(); |
|
180 } |
|
181 return gGonkPermissionService; |
|
182 } |
|
183 |
|
184 void |
|
185 GonkPermissionService::addGrantInfo(const char* permission, int32_t pid) |
|
186 { |
|
187 mGrantArray.AppendElement(PermissionGrant(permission, pid)); |
|
188 } |