1 #region Copyright notice and license
2 
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #endregion
18 
19 using System;
20 using System.Collections.Concurrent;
21 using System.Diagnostics;
22 using System.IO;
23 using System.Reflection;
24 using System.Runtime.InteropServices;
25 using System.Threading;
26 using Grpc.Core.Utils;
27 
28 namespace Grpc.Core.Internal
29 {
30     /// <summary>
31     /// Utility methods for detecting platform and architecture.
32     /// </summary>
33     internal static class PlatformApis
34     {
35         const string UnityEngineApplicationClassName = "UnityEngine.Application, UnityEngine";
36         const string XamarinAndroidObjectClassName = "Java.Lang.Object, Mono.Android";
37         const string XamarinIOSObjectClassName = "Foundation.NSObject, Xamarin.iOS";
38 
39         static readonly bool isLinux;
40         static readonly bool isMacOSX;
41         static readonly bool isWindows;
42         static readonly bool isMono;
43         static readonly bool isNetCore;
44         static readonly bool isUnity;
45         static readonly bool isUnityIOS;
46         static readonly bool isXamarin;
47         static readonly bool isXamarinIOS;
48         static readonly bool isXamarinAndroid;
49 
PlatformApis()50         static PlatformApis()
51         {
52 #if NETSTANDARD1_5 || NETSTANDARD2_0
53             isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
54             isMacOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
55             isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
56             isNetCore = RuntimeInformation.FrameworkDescription.StartsWith(".NET Core");
57 #else
58             var platform = Environment.OSVersion.Platform;
59 
60             // PlatformID.MacOSX is never returned, commonly used trick is to identify Mac is by using uname.
61             isMacOSX = (platform == PlatformID.Unix && GetUname() == "Darwin");
62             isLinux = (platform == PlatformID.Unix && !isMacOSX);
63             isWindows = (platform == PlatformID.Win32NT || platform == PlatformID.Win32S || platform == PlatformID.Win32Windows);
64             isNetCore = false;
65 #endif
66             isMono = Type.GetType("Mono.Runtime") != null;
67 
68             // Unity
69             var unityApplicationClass = Type.GetType(UnityEngineApplicationClassName);
70             if (unityApplicationClass != null)
71             {
72                 isUnity = true;
73                 // Consult value of Application.platform via reflection
74                 // https://docs.unity3d.com/ScriptReference/Application-platform.html
75                 var platformProperty = unityApplicationClass.GetTypeInfo().GetProperty("platform");
76                 var unityRuntimePlatform = platformProperty?.GetValue(null)?.ToString();
77                 isUnityIOS = (unityRuntimePlatform == "IPhonePlayer");
78             }
79             else
80             {
81                 isUnity = false;
82                 isUnityIOS = false;
83             }
84 
85             // Xamarin
86             isXamarinIOS = Type.GetType(XamarinIOSObjectClassName) != null;
87             isXamarinAndroid = Type.GetType(XamarinAndroidObjectClassName) != null;
88             isXamarin = isXamarinIOS || isXamarinAndroid;
89         }
90 
91         public static bool IsLinux
92         {
93             get { return isLinux; }
94         }
95 
96         public static bool IsMacOSX
97         {
98             get { return isMacOSX; }
99         }
100 
101         public static bool IsWindows
102         {
103             get { return isWindows; }
104         }
105 
106         public static bool IsMono
107         {
108             get { return isMono; }
109         }
110 
111         /// <summary>
112         /// true if running on Unity platform.
113         /// </summary>
114         public static bool IsUnity
115         {
116             get { return isUnity; }
117         }
118 
119         /// <summary>
120         /// true if running on Unity iOS, false otherwise.
121         /// </summary>
122         public static bool IsUnityIOS
123         {
124             get { return isUnityIOS; }
125         }
126 
127         /// <summary>
128         /// true if running on a Xamarin platform (either Xamarin.Android or Xamarin.iOS),
129         /// false otherwise.
130         /// </summary>
131         public static bool IsXamarin
132         {
133             get { return isXamarin; }
134         }
135 
136         /// <summary>
137         /// true if running on Xamarin.iOS, false otherwise.
138         /// </summary>
139         public static bool IsXamarinIOS
140         {
141             get { return isXamarinIOS; }
142         }
143 
144         /// <summary>
145         /// true if running on Xamarin.Android, false otherwise.
146         /// </summary>
147         public static bool IsXamarinAndroid
148         {
149             get { return isXamarinAndroid; }
150         }
151 
152         /// <summary>
153         /// true if running on .NET Core (CoreCLR), false otherwise.
154         /// </summary>
155         public static bool IsNetCore
156         {
157             get { return isNetCore; }
158         }
159 
160         public static bool Is64Bit
161         {
162             get { return IntPtr.Size == 8; }
163         }
164 
165         /// <summary>
166         /// Returns <c>UnityEngine.Application.platform</c> as a string.
167         /// See https://docs.unity3d.com/ScriptReference/Application-platform.html for possible values.
168         /// Value is obtained via reflection to avoid compile-time dependency on Unity.
169         /// This method should only be called if <c>IsUnity</c> is <c>true</c>.
170         /// </summary>
GetUnityRuntimePlatform()171         public static string GetUnityRuntimePlatform()
172         {
173             GrpcPreconditions.CheckState(IsUnity, "Not running on Unity.");
174 #if NETSTANDARD1_5 || NETSTANDARD2_0
175             return Type.GetType(UnityEngineApplicationClassName).GetTypeInfo().GetProperty("platform").GetValue(null).ToString();
176 #else
177             return Type.GetType(UnityEngineApplicationClassName).GetProperty("platform").GetValue(null).ToString();
178 #endif
179         }
180 
181         [DllImport("libc")]
uname(IntPtr buf)182         static extern int uname(IntPtr buf);
183 
GetUname()184         static string GetUname()
185         {
186             var buffer = Marshal.AllocHGlobal(8192);
187             try
188             {
189                 if (uname(buffer) == 0)
190                 {
191                     return Marshal.PtrToStringAnsi(buffer);
192                 }
193                 return string.Empty;
194             }
195             catch
196             {
197                 return string.Empty;
198             }
199             finally
200             {
201                 if (buffer != IntPtr.Zero)
202                 {
203                     Marshal.FreeHGlobal(buffer);
204                 }
205             }
206         }
207     }
208 }
209