--- /dev/null
+#!/usr/bin/env python3
+
+import subprocess, os, argparse
+
+from time import sleep
+from getpass import getpass
+
+# Default .NET application used in TV
+pre_app_lists = [
+ "com.samsung.tv.csfs",
+ "com.samsung.tv.mycontents",
+ "com.samsung.tv.samsung-health",
+ "com.samsung.tv.searchall",
+ "com.samsung.tv.social-chat-app",
+ "com.samsung.tv.store"]
+
+# Default system module used for candidate process in TV
+pre_system_module_lists = [
+ "System.Private.CoreLib",
+ "Tizen.NUI",
+ "System.Net.Http",
+ "System.Text.Json"]
+
+tizen_profile_data_path = "/home/owner/data/.__tizen_candidate_profile_data"
+
+def cmd(command):
+ return subprocess.run((f"sdb -s {serial_num} " + command).split(), encoding="utf-8", stdout=subprocess.PIPE)
+
+
+def download_mcj_edit():
+ if not os.path.exists("mcj-edit.py"):
+ print("Download mcj-edit.py: Start")
+
+ user_id = input("Username for 'https://github.sec.samsung.net': ")
+ password = getpass(f"Password for 'https://{user_id}@github.sec.samsung.net': ")
+ subprocess.Popen((f"curl -L -O https://raw.github.sec.samsung.net/dotnet/runtime/release/6.0-tizen/src/coreclr/tools/mcj-edit/mcj-edit.py -u {user_id}:{password} -v").split(), encoding="utf-8", stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout
+ sleep(3)
+ with open("mcj-edit.py", 'r') as f:
+ if "404: Not Found" == f.readline():
+ print("\nremote: Invalid username or password.")
+ os.remove("mcj-edit.py")
+ exit(1)
+
+ print("Download mcj-edit.py: End")
+
+
+def get_profile():
+ print("Get profile data: Start")
+
+ for app in app_ids:
+ print(f"Kill appId: {app}")
+ cmd(f"shell app_launcher -t {app}")
+ cmd(f"shell dotnettool --rm-app-profile {app}")
+ sleep(3)
+
+ cmd(f"shell cp {tizen_profile_data_path} {tizen_profile_data_path}.origin")
+ cmd(f"shell rm {tizen_profile_data_path}")
+ cmd(f'shell killall dotnet-hydra-loader dotnet-loader')
+ sleep(30)
+
+ for app in app_ids:
+ print(f"Launch appId: {app}")
+ cmd(f"shell app_launcher -s {app}")
+ sleep(30)
+ cmd(f"shell app_launcher -t {app}")
+ cmd(f"pull /home/owner/apps_rw/{app}/data/.__tizen_specific_profile_data {app}")
+ sleep(3)
+
+ print("Get profile data: End")
+
+
+def split_profile():
+ print("Split profile data: Start")
+
+ system_module_path = ""
+ with open("system_module", 'w') as f:
+ for module in sys_modules:
+ f.write(module+"\n")
+ print(f"System modules: {module}")
+
+ for app in app_ids:
+ print(f"Split appId: {app}")
+ subprocess.run((f"python3 mcj-edit.py split -i {app} --system-modules-list system_module").split(), encoding="utf-8", stdout=subprocess.PIPE)
+ sleep(3)
+
+ os.remove("system_module")
+
+ print("Split profile data: End")
+
+
+def set_profile():
+ cmd(f"shell chsmack -a User::App::Shared {tizen_profile_data_path}")
+ cmd(f"shell chown owner:users {tizen_profile_data_path}")
+ cmd(f"shell chmod 644 {tizen_profile_data_path}")
+ cmd(f"shell rm {tizen_profile_data_path}.origin")
+ os.remove("mcj-edit.py")
+
+ for app in app_ids:
+ subprocess.run((f"rm {app}").split(), encoding="utf-8", stdout=subprocess.PIPE)
+ subprocess.run((f"rm {app}.app").split(), encoding="utf-8", stdout=subprocess.PIPE)
+ subprocess.run((f"rm {app}.sys").split(), encoding="utf-8", stdout=subprocess.PIPE)
+
+
+def merge_profile():
+ print("Merge profile data: Start")
+
+ app_sys_lists = ""
+ for app in app_ids:
+ app_sys_lists += f"-i {app}.sys "
+
+ subprocess.run((f"python3 mcj-edit.py merge " + app_sys_lists + "-o .__tizen_candidate_profile_data").split(), encoding="utf-8", stdout=subprocess.PIPE)
+ sleep(3)
+
+ print("Merge profile data: End")
+
+ if not os.path.exists(f".__tizen_candidate_profile_data"):
+ cmd(f"shell cp {tizen_profile_data_path}.origin {tizen_profile_data_path}")
+ set_profile()
+ print("Candidate profile data generation: FAIL")
+ exit(1)
+ else:
+ cmd(f"push .__tizen_candidate_profile_data /home/owner/data/")
+ set_profile()
+ print("Candidate profile data generation: SUCCESS")
+
+
+def read_serial():
+ global serial_num
+
+ raw = subprocess.run(("sdb devices").split(), encoding="utf-8", stdout=subprocess.PIPE).stdout
+ lines = [l for l in raw.splitlines() if not l.startswith("* ")]
+ if len(lines) <= 1:
+ serial_num = None
+ elif len(lines) == 2:
+ serial_num = lines[1].split(" ")[0].split(":")[0].strip()
+ else:
+ serials = []
+ for idx in range(1, len(lines)):
+ serial = lines[idx].split(" ")[0].split(":")[0].replace("device", "").strip()
+ serials.append(serial)
+ print(f"[{idx}] {serial} - {lines[idx].split(' ')[2].strip()}")
+ choice = input(f"Select a device [1-{len(lines) - 1}]: ")
+ serial_num = serials[int(choice) - 1].strip() if choice.isdigit() else None
+ return serial_num
+
+
+def main():
+ epilog = \
+ '''Reference link :
+ https://github.sec.samsung.net/dotnet/runtime/blob/release/6.0-tizen/src/coreclr/tools/mcj-edit/README.md
+ '''
+
+ global app_ids, sys_modules
+
+ parser = argparse.ArgumentParser(description="Profile data generation tools to use in candidate process", epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
+ parser.add_argument("-a", metavar="APP_ID", nargs="*", type=str, help='target app ids (default: predefined 6 applications)', default=pre_app_lists)
+ parser.add_argument("-s", metavar="SYS_MODULE", nargs="*", type=str, help='system module lists (default: predefined 4 system modules)', default=pre_system_module_lists)
+ args = parser.parse_args()
+ app_ids = args.a
+ sys_modules = args.s
+
+ serial = read_serial()
+ if serial is None:
+ print("No connected device(s).")
+ exit(1)
+
+ cmd(f"root on")
+ cmd(f"shell mount -o remount,rw /")
+
+ download_mcj_edit();
+ get_profile()
+ split_profile()
+ merge_profile()
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ exit(1)