• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
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 package com.android.server.firewall;
18 
19 import android.annotation.NonNull;
20 import android.app.AppGlobals;
21 import android.content.ComponentName;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.IPackageManager;
26 import android.content.pm.PackageManager;
27 import android.content.pm.PackageManagerInternal;
28 import android.os.Environment;
29 import android.os.FileObserver;
30 import android.os.Handler;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.os.RemoteException;
34 import android.util.ArrayMap;
35 import android.util.Slog;
36 import android.util.Xml;
37 
38 import com.android.internal.util.ArrayUtils;
39 import com.android.internal.util.XmlUtils;
40 import com.android.server.EventLogTags;
41 import com.android.server.IntentResolver;
42 import com.android.server.LocalServices;
43 import com.android.server.pm.Computer;
44 
45 import org.xmlpull.v1.XmlPullParser;
46 import org.xmlpull.v1.XmlPullParserException;
47 
48 import java.io.File;
49 import java.io.FileInputStream;
50 import java.io.FileNotFoundException;
51 import java.io.IOException;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.HashMap;
55 import java.util.List;
56 
57 public class IntentFirewall {
58     static final String TAG = "IntentFirewall";
59 
60     // e.g. /data/system/ifw or /data/secure/system/ifw
61     private static final File RULES_DIR = new File(Environment.getDataSystemDirectory(), "ifw");
62 
63     private static final int LOG_PACKAGES_MAX_LENGTH = 150;
64     private static final int LOG_PACKAGES_SUFFICIENT_LENGTH = 125;
65 
66     private static final String TAG_RULES = "rules";
67     private static final String TAG_ACTIVITY = "activity";
68     private static final String TAG_SERVICE = "service";
69     private static final String TAG_BROADCAST = "broadcast";
70 
71     private static final int TYPE_ACTIVITY = 0;
72     private static final int TYPE_BROADCAST = 1;
73     private static final int TYPE_SERVICE = 2;
74 
75     private static final HashMap<String, FilterFactory> factoryMap;
76 
77     private final AMSInterface mAms;
78 
79     private final RuleObserver mObserver;
80 
81     @NonNull
82     private PackageManagerInternal mPackageManager;
83 
84     private FirewallIntentResolver mActivityResolver = new FirewallIntentResolver();
85     private FirewallIntentResolver mBroadcastResolver = new FirewallIntentResolver();
86     private FirewallIntentResolver mServiceResolver = new FirewallIntentResolver();
87 
88     static {
89         FilterFactory[] factories = new FilterFactory[] {
90                 AndFilter.FACTORY,
91                 OrFilter.FACTORY,
92                 NotFilter.FACTORY,
93 
94                 StringFilter.ACTION,
95                 StringFilter.COMPONENT,
96                 StringFilter.COMPONENT_NAME,
97                 StringFilter.COMPONENT_PACKAGE,
98                 StringFilter.DATA,
99                 StringFilter.HOST,
100                 StringFilter.MIME_TYPE,
101                 StringFilter.SCHEME,
102                 StringFilter.PATH,
103                 StringFilter.SSP,
104 
105                 CategoryFilter.FACTORY,
106                 SenderFilter.FACTORY,
107                 SenderPackageFilter.FACTORY,
108                 SenderPermissionFilter.FACTORY,
109                 PortFilter.FACTORY
110         };
111 
112         // load factor ~= .75
113         factoryMap = new HashMap<String, FilterFactory>(factories.length * 4 / 3);
114         for (int i=0; i<factories.length; i++) {
115             FilterFactory factory = factories[i];
factory.getTagName()116             factoryMap.put(factory.getTagName(), factory);
117         }
118     }
119 
IntentFirewall(AMSInterface ams, Handler handler)120     public IntentFirewall(AMSInterface ams, Handler handler) {
121         mAms = ams;
122         mHandler = new FirewallHandler(handler.getLooper());
123         File rulesDir = getRulesDir();
124         rulesDir.mkdirs();
125 
126         readRulesDir(rulesDir);
127 
128         mObserver = new RuleObserver(rulesDir);
129         mObserver.startWatching();
130     }
131 
getPackageManager()132     private PackageManagerInternal getPackageManager() {
133         if (mPackageManager == null) {
134             mPackageManager = LocalServices.getService(PackageManagerInternal.class);
135         }
136         return mPackageManager;
137     }
138 
139     /**
140      * This is called from ActivityManager to check if a start activity intent should be allowed.
141      * It is assumed the caller is already holding the global ActivityManagerService lock.
142      */
checkStartActivity(Intent intent, int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp)143     public boolean checkStartActivity(Intent intent, int callerUid, int callerPid,
144             String resolvedType, ApplicationInfo resolvedApp) {
145         return checkIntent(mActivityResolver, intent.getComponent(), TYPE_ACTIVITY, intent,
146                 callerUid, callerPid, resolvedType, resolvedApp.uid);
147     }
148 
checkService(ComponentName resolvedService, Intent intent, int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp)149     public boolean checkService(ComponentName resolvedService, Intent intent, int callerUid,
150             int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
151         return checkIntent(mServiceResolver, resolvedService, TYPE_SERVICE, intent, callerUid,
152                 callerPid, resolvedType, resolvedApp.uid);
153     }
154 
checkBroadcast(Intent intent, int callerUid, int callerPid, String resolvedType, int receivingUid)155     public boolean checkBroadcast(Intent intent, int callerUid, int callerPid,
156             String resolvedType, int receivingUid) {
157         return checkIntent(mBroadcastResolver, intent.getComponent(), TYPE_BROADCAST, intent,
158                 callerUid, callerPid, resolvedType, receivingUid);
159     }
160 
checkIntent(FirewallIntentResolver resolver, ComponentName resolvedComponent, int intentType, Intent intent, int callerUid, int callerPid, String resolvedType, int receivingUid)161     public boolean checkIntent(FirewallIntentResolver resolver, ComponentName resolvedComponent,
162             int intentType, Intent intent, int callerUid, int callerPid, String resolvedType,
163             int receivingUid) {
164         boolean log = false;
165         boolean block = false;
166 
167         // For the first pass, find all the rules that have at least one intent-filter or
168         // component-filter that matches this intent
169         List<Rule> candidateRules;
170         candidateRules = resolver.queryIntent(getPackageManager().snapshot(), intent, resolvedType,
171                 false /*defaultOnly*/, 0);
172         if (candidateRules == null) {
173             candidateRules = new ArrayList<Rule>();
174         }
175         resolver.queryByComponent(resolvedComponent, candidateRules);
176 
177         // For the second pass, try to match the potentially more specific conditions in each
178         // rule against the intent
179         for (int i=0; i<candidateRules.size(); i++) {
180             Rule rule = candidateRules.get(i);
181             if (rule.matches(this, resolvedComponent, intent, callerUid, callerPid, resolvedType,
182                     receivingUid)) {
183                 block |= rule.getBlock();
184                 log |= rule.getLog();
185 
186                 // if we've already determined that we should both block and log, there's no need
187                 // to continue trying rules
188                 if (block && log) {
189                     break;
190                 }
191             }
192         }
193 
194         if (log) {
195             logIntent(intentType, intent, callerUid, resolvedType);
196         }
197 
198         return !block;
199     }
200 
logIntent(int intentType, Intent intent, int callerUid, String resolvedType)201     private static void logIntent(int intentType, Intent intent, int callerUid,
202             String resolvedType) {
203         // The component shouldn't be null, but let's double check just to be safe
204         ComponentName cn = intent.getComponent();
205         String shortComponent = null;
206         if (cn != null) {
207             shortComponent = cn.flattenToShortString();
208         }
209 
210         String callerPackages = null;
211         int callerPackageCount = 0;
212         IPackageManager pm = AppGlobals.getPackageManager();
213         if (pm != null) {
214             try {
215                 String[] callerPackagesArray = pm.getPackagesForUid(callerUid);
216                 if (callerPackagesArray != null) {
217                     callerPackageCount = callerPackagesArray.length;
218                     callerPackages = joinPackages(callerPackagesArray);
219                 }
220             } catch (RemoteException ex) {
221                 Slog.e(TAG, "Remote exception while retrieving packages", ex);
222             }
223         }
224 
225         EventLogTags.writeIfwIntentMatched(intentType, shortComponent, callerUid,
226                 callerPackageCount, callerPackages, intent.getAction(), resolvedType,
227                 intent.getDataString(), intent.getFlags());
228     }
229 
230     /**
231      * Joins a list of package names such that the resulting string is no more than
232      * LOG_PACKAGES_MAX_LENGTH.
233      *
234      * Only full package names will be added to the result, unless every package is longer than the
235      * limit, in which case one of the packages will be truncated and added. In this case, an
236      * additional '-' character will be added to the end of the string, to denote the truncation.
237      *
238      * If it encounters a package that won't fit in the remaining space, it will continue on to the
239      * next package, unless the total length of the built string so far is greater than
240      * LOG_PACKAGES_SUFFICIENT_LENGTH, in which case it will stop and return what it has.
241      */
joinPackages(String[] packages)242     private static String joinPackages(String[] packages) {
243         boolean first = true;
244         StringBuilder sb = new StringBuilder();
245         for (int i=0; i<packages.length; i++) {
246             String pkg = packages[i];
247 
248             // + 1 length for the comma. This logic technically isn't correct for the first entry,
249             // but it's not critical.
250             if (sb.length() + pkg.length() + 1 < LOG_PACKAGES_MAX_LENGTH) {
251                 if (!first) {
252                     sb.append(',');
253                 } else {
254                     first = false;
255                 }
256                 sb.append(pkg);
257             } else if (sb.length() >= LOG_PACKAGES_SUFFICIENT_LENGTH) {
258                 return sb.toString();
259             }
260         }
261         if (sb.length() == 0 && packages.length > 0) {
262             String pkg = packages[0];
263             // truncating from the end - the last part of the package name is more likely to be
264             // interesting/unique
265             return pkg.substring(pkg.length() - LOG_PACKAGES_MAX_LENGTH + 1) + '-';
266         }
267         return null;
268     }
269 
getRulesDir()270     public static File getRulesDir() {
271         return RULES_DIR;
272     }
273 
274     /**
275      * Reads rules from all xml files (*.xml) in the given directory, and replaces our set of rules
276      * with the newly read rules.
277      *
278      * We only check for files ending in ".xml", to allow for temporary files that are atomically
279      * renamed to .xml
280      *
281      * All calls to this method from the file observer come through a handler and are inherently
282      * serialized
283      */
readRulesDir(File rulesDir)284     private void readRulesDir(File rulesDir) {
285         FirewallIntentResolver[] resolvers = new FirewallIntentResolver[3];
286         for (int i=0; i<resolvers.length; i++) {
287             resolvers[i] = new FirewallIntentResolver();
288         }
289 
290         File[] files = rulesDir.listFiles();
291         if (files != null) {
292             for (int i=0; i<files.length; i++) {
293                 File file = files[i];
294 
295                 if (file.getName().endsWith(".xml")) {
296                     readRules(file, resolvers);
297                 }
298             }
299         }
300 
301         Slog.i(TAG, "Read new rules (A:" + resolvers[TYPE_ACTIVITY].filterSet().size() +
302                 " B:" + resolvers[TYPE_BROADCAST].filterSet().size() +
303                 " S:" + resolvers[TYPE_SERVICE].filterSet().size() + ")");
304 
305         synchronized (mAms.getAMSLock()) {
306             mActivityResolver = resolvers[TYPE_ACTIVITY];
307             mBroadcastResolver = resolvers[TYPE_BROADCAST];
308             mServiceResolver = resolvers[TYPE_SERVICE];
309         }
310     }
311 
312     /**
313      * Reads rules from the given file and add them to the given resolvers
314      */
readRules(File rulesFile, FirewallIntentResolver[] resolvers)315     private void readRules(File rulesFile, FirewallIntentResolver[] resolvers) {
316         // some temporary lists to hold the rules while we parse the xml file, so that we can
317         // add the rules all at once, after we know there weren't any major structural problems
318         // with the xml file
319         List<List<Rule>> rulesByType = new ArrayList<List<Rule>>(3);
320         for (int i=0; i<3; i++) {
321             rulesByType.add(new ArrayList<Rule>());
322         }
323 
324         FileInputStream fis;
325         try {
326             fis = new FileInputStream(rulesFile);
327         } catch (FileNotFoundException ex) {
328             // Nope, no rules. Nothing else to do!
329             return;
330         }
331 
332         try {
333             XmlPullParser parser = Xml.newPullParser();
334 
335             parser.setInput(fis, null);
336 
337             XmlUtils.beginDocument(parser, TAG_RULES);
338 
339             int outerDepth = parser.getDepth();
340             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
341                 int ruleType = -1;
342 
343                 String tagName = parser.getName();
344                 if (tagName.equals(TAG_ACTIVITY)) {
345                     ruleType = TYPE_ACTIVITY;
346                 } else if (tagName.equals(TAG_BROADCAST)) {
347                     ruleType = TYPE_BROADCAST;
348                 } else if (tagName.equals(TAG_SERVICE)) {
349                     ruleType = TYPE_SERVICE;
350                 }
351 
352                 if (ruleType != -1) {
353                     Rule rule = new Rule();
354 
355                     List<Rule> rules = rulesByType.get(ruleType);
356 
357                     // if we get an error while parsing a particular rule, we'll just ignore
358                     // that rule and continue on with the next rule
359                     try {
360                         rule.readFromXml(parser);
361                     } catch (XmlPullParserException ex) {
362                         Slog.e(TAG, "Error reading an intent firewall rule from " + rulesFile, ex);
363                         continue;
364                     }
365 
366                     rules.add(rule);
367                 }
368             }
369         } catch (XmlPullParserException ex) {
370             // if there was an error outside of a specific rule, then there are probably
371             // structural problems with the xml file, and we should completely ignore it
372             Slog.e(TAG, "Error reading intent firewall rules from " + rulesFile, ex);
373             return;
374         } catch (IOException ex) {
375             Slog.e(TAG, "Error reading intent firewall rules from " + rulesFile, ex);
376             return;
377         } finally {
378             try {
379                 fis.close();
380             } catch (IOException ex) {
381                 Slog.e(TAG, "Error while closing " + rulesFile, ex);
382             }
383         }
384 
385         for (int ruleType=0; ruleType<rulesByType.size(); ruleType++) {
386             List<Rule> rules = rulesByType.get(ruleType);
387             FirewallIntentResolver resolver = resolvers[ruleType];
388 
389             for (int ruleIndex=0; ruleIndex<rules.size(); ruleIndex++) {
390                 Rule rule = rules.get(ruleIndex);
391                 for (int i=0; i<rule.getIntentFilterCount(); i++) {
392                     resolver.addFilter(null, rule.getIntentFilter(i));
393                 }
394                 for (int i=0; i<rule.getComponentFilterCount(); i++) {
395                     resolver.addComponentFilter(rule.getComponentFilter(i), rule);
396                 }
397             }
398         }
399     }
400 
parseFilter(XmlPullParser parser)401     static Filter parseFilter(XmlPullParser parser) throws IOException, XmlPullParserException {
402         String elementName = parser.getName();
403 
404         FilterFactory factory = factoryMap.get(elementName);
405 
406         if (factory == null) {
407             throw new XmlPullParserException("Unknown element in filter list: " + elementName);
408         }
409         return factory.newFilter(parser);
410     }
411 
412     /**
413      * Represents a single activity/service/broadcast rule within one of the xml files.
414      *
415      * Rules are matched against an incoming intent in two phases. The goal of the first phase
416      * is to select a subset of rules that might match a given intent.
417      *
418      * For the first phase, we use a combination of intent filters (via an IntentResolver)
419      * and component filters to select which rules to check. If a rule has multiple intent or
420      * component filters, only a single filter must match for the rule to be passed on to the
421      * second phase.
422      *
423      * In the second phase, we check the specific conditions in each rule against the values in the
424      * intent. All top level conditions (but not filters) in the rule must match for the rule as a
425      * whole to match.
426      *
427      * If the rule matches, then we block or log the intent, as specified by the rule. If multiple
428      * rules match, we combine the block/log flags from any matching rule.
429      */
430     private static class Rule extends AndFilter {
431         private static final String TAG_INTENT_FILTER = "intent-filter";
432         private static final String TAG_COMPONENT_FILTER = "component-filter";
433         private static final String ATTR_NAME = "name";
434 
435         private static final String ATTR_BLOCK = "block";
436         private static final String ATTR_LOG = "log";
437 
438         private final ArrayList<FirewallIntentFilter> mIntentFilters =
439                 new ArrayList<FirewallIntentFilter>(1);
440         private final ArrayList<ComponentName> mComponentFilters = new ArrayList<ComponentName>(0);
441         private boolean block;
442         private boolean log;
443 
444         @Override
readFromXml(XmlPullParser parser)445         public Rule readFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
446             block = Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_BLOCK));
447             log = Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_LOG));
448 
449             super.readFromXml(parser);
450             return this;
451         }
452 
453         @Override
readChild(XmlPullParser parser)454         protected void readChild(XmlPullParser parser) throws IOException, XmlPullParserException {
455             String currentTag = parser.getName();
456 
457             if (currentTag.equals(TAG_INTENT_FILTER)) {
458                 FirewallIntentFilter intentFilter = new FirewallIntentFilter(this);
459                 intentFilter.readFromXml(parser);
460                 mIntentFilters.add(intentFilter);
461             } else if (currentTag.equals(TAG_COMPONENT_FILTER)) {
462                 String componentStr = parser.getAttributeValue(null, ATTR_NAME);
463                 if (componentStr == null) {
464                     throw new XmlPullParserException("Component name must be specified.",
465                             parser, null);
466                 }
467 
468                 ComponentName componentName = ComponentName.unflattenFromString(componentStr);
469                 if (componentName == null) {
470                     throw new XmlPullParserException("Invalid component name: " + componentStr);
471                 }
472 
473                 mComponentFilters.add(componentName);
474             } else {
475                 super.readChild(parser);
476             }
477         }
478 
getIntentFilterCount()479         public int getIntentFilterCount() {
480             return mIntentFilters.size();
481         }
482 
getIntentFilter(int index)483         public FirewallIntentFilter getIntentFilter(int index) {
484             return mIntentFilters.get(index);
485         }
486 
getComponentFilterCount()487         public int getComponentFilterCount() {
488             return mComponentFilters.size();
489         }
490 
getComponentFilter(int index)491         public ComponentName getComponentFilter(int index) {
492             return mComponentFilters.get(index);
493         }
getBlock()494         public boolean getBlock() {
495             return block;
496         }
497 
getLog()498         public boolean getLog() {
499             return log;
500         }
501     }
502 
503     private static class FirewallIntentFilter extends IntentFilter {
504         private final Rule rule;
505 
FirewallIntentFilter(Rule rule)506         public FirewallIntentFilter(Rule rule) {
507             this.rule = rule;
508         }
509     }
510 
511     private static class FirewallIntentResolver
512             extends IntentResolver<FirewallIntentFilter, Rule> {
513         @Override
allowFilterResult(FirewallIntentFilter filter, List<Rule> dest)514         protected boolean allowFilterResult(FirewallIntentFilter filter, List<Rule> dest) {
515             return !dest.contains(filter.rule);
516         }
517 
518         @Override
isPackageForFilter(String packageName, FirewallIntentFilter filter)519         protected boolean isPackageForFilter(String packageName, FirewallIntentFilter filter) {
520             return true;
521         }
522 
523         @Override
newArray(int size)524         protected FirewallIntentFilter[] newArray(int size) {
525             return new FirewallIntentFilter[size];
526         }
527 
528         @Override
newResult(@onNull Computer computer, FirewallIntentFilter filter, int match, int userId, long customFlags)529         protected Rule newResult(@NonNull Computer computer, FirewallIntentFilter filter,
530                 int match, int userId, long customFlags) {
531             return filter.rule;
532         }
533 
534         @Override
sortResults(List<Rule> results)535         protected void sortResults(List<Rule> results) {
536             // there's no need to sort the results
537             return;
538         }
539 
540         @Override
getIntentFilter(@onNull FirewallIntentFilter input)541         protected IntentFilter getIntentFilter(@NonNull FirewallIntentFilter input) {
542             return input;
543         }
544 
queryByComponent(ComponentName componentName, List<Rule> candidateRules)545         public void queryByComponent(ComponentName componentName, List<Rule> candidateRules) {
546             Rule[] rules = mRulesByComponent.get(componentName);
547             if (rules != null) {
548                 candidateRules.addAll(Arrays.asList(rules));
549             }
550         }
551 
addComponentFilter(ComponentName componentName, Rule rule)552         public void addComponentFilter(ComponentName componentName, Rule rule) {
553             Rule[] rules = mRulesByComponent.get(componentName);
554             rules = ArrayUtils.appendElement(Rule.class, rules, rule);
555             mRulesByComponent.put(componentName, rules);
556         }
557 
558         private final ArrayMap<ComponentName, Rule[]> mRulesByComponent =
559                 new ArrayMap<ComponentName, Rule[]>(0);
560     }
561 
562     final FirewallHandler mHandler;
563 
564     private final class FirewallHandler extends Handler {
FirewallHandler(Looper looper)565         public FirewallHandler(Looper looper) {
566             super(looper, null, true);
567         }
568 
569         @Override
handleMessage(Message msg)570         public void handleMessage(Message msg) {
571             readRulesDir(getRulesDir());
572         }
573     };
574 
575     /**
576      * Monitors for the creation/deletion/modification of any .xml files in the rule directory
577      */
578     private class RuleObserver extends FileObserver {
579         private static final int MONITORED_EVENTS = FileObserver.CREATE|FileObserver.MOVED_TO|
580                 FileObserver.CLOSE_WRITE|FileObserver.DELETE|FileObserver.MOVED_FROM;
581 
RuleObserver(File monitoredDir)582         public RuleObserver(File monitoredDir) {
583             super(monitoredDir.getAbsolutePath(), MONITORED_EVENTS);
584         }
585 
586         @Override
onEvent(int event, String path)587         public void onEvent(int event, String path) {
588             if (path != null && path.endsWith(".xml")) {
589                 // we wait 250ms before taking any action on an event, in order to dedup multiple
590                 // events. E.g. a delete event followed by a create event followed by a subsequent
591                 // write+close event
592                 mHandler.removeMessages(0);
593                 mHandler.sendEmptyMessageDelayed(0, 250);
594             }
595         }
596     }
597 
598     /**
599      * This interface contains the methods we need from ActivityManagerService. This allows AMS to
600      * export these methods to us without making them public, and also makes it easier to test this
601      * component.
602      */
603     public interface AMSInterface {
checkComponentPermission(String permission, int pid, int uid, int owningUid, boolean exported)604         int checkComponentPermission(String permission, int pid, int uid,
605                 int owningUid, boolean exported);
getAMSLock()606         Object getAMSLock();
607     }
608 
609     /**
610      * Checks if the caller has access to a component
611      *
612      * @param permission If present, the caller must have this permission
613      * @param pid The pid of the caller
614      * @param uid The uid of the caller
615      * @param owningUid The uid of the application that owns the component
616      * @param exported Whether the component is exported
617      * @return True if the caller can access the described component
618      */
checkComponentPermission(String permission, int pid, int uid, int owningUid, boolean exported)619     boolean checkComponentPermission(String permission, int pid, int uid, int owningUid,
620             boolean exported) {
621         return mAms.checkComponentPermission(permission, pid, uid, owningUid, exported) ==
622                 PackageManager.PERMISSION_GRANTED;
623     }
624 
signaturesMatch(int uid1, int uid2)625     boolean signaturesMatch(int uid1, int uid2) {
626         try {
627             IPackageManager pm = AppGlobals.getPackageManager();
628             return pm.checkUidSignatures(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
629         } catch (RemoteException ex) {
630             Slog.e(TAG, "Remote exception while checking signatures", ex);
631             return false;
632         }
633     }
634 
635 }
636