1 /*
2 * Copyright (C) 2024 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 #include <unistd.h>
17
18 #include <regex>
19
20 #include <android-base/logging.h>
21 #include <android-base/properties.h>
22 #include <android-base/strings.h>
23
24 #if defined(__ANDROID__)
25 #include <log/log_properties.h>
26 #include "selinux/android.h"
27 #endif
28
29 #if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
30 #include <com_android_tradeinmode_flags.h>
31 #endif
32
33 static bool in_tradeinmode = false;
34 static constexpr char kTradeInModeProp[] = "persist.adb.tradeinmode";
35
36 static constexpr int TIM_DISABLED = -1;
37 static constexpr int TIM_UNSET = 0;
38 static constexpr int TIM_FOYER = 1;
39 static constexpr int TIM_EVALUATION_MODE = 2;
40
should_enter_tradeinmode()41 bool should_enter_tradeinmode() {
42 #if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
43 if (!com_android_tradeinmode_flags_enable_trade_in_mode()) {
44 return false;
45 }
46 return android::base::GetIntProperty(kTradeInModeProp, TIM_UNSET) == TIM_FOYER;
47 #else
48 return false;
49 #endif
50 }
51
enter_tradeinmode(const char * seclabel)52 void enter_tradeinmode(const char* seclabel) {
53 #if defined(__ANDROID__)
54 if (selinux_android_setcon(seclabel) < 0) {
55 PLOG(ERROR) << "Could not set SELinux context";
56
57 // Flag TIM as failed so we don't enter a restart loop.
58 android::base::SetProperty(kTradeInModeProp, std::to_string(TIM_DISABLED));
59
60 _exit(1);
61 }
62
63 // Keep a separate global flag for TIM in case the property changes (for
64 // example, if it's set while as root for testing).
65 in_tradeinmode = true;
66 #endif
67 }
68
is_in_tradeinmode()69 bool is_in_tradeinmode() {
70 return in_tradeinmode;
71 }
72
is_in_tradein_evaluation_mode()73 bool is_in_tradein_evaluation_mode() {
74 return android::base::GetIntProperty(kTradeInModeProp, TIM_UNSET) == TIM_EVALUATION_MODE;
75 }
76
allow_tradeinmode_command(std::string_view name)77 bool allow_tradeinmode_command(std::string_view name) {
78 #if defined(__ANDROID__)
79 // Allow "adb root" from trade-in-mode so that automated testing is possible.
80 if (__android_log_is_debuggable() && android::base::ConsumePrefix(&name, "root:")) {
81 return true;
82 }
83 #endif
84
85 // Allow "shell tradeinmode" with only simple arguments.
86 std::regex tim_pattern("shell[^:]*:tradeinmode(\\s*|\\s[A-Za-z0-9_\\-\\s]*)");
87 return std::regex_match(std::string(name), tim_pattern);
88 }
89