The action hook after_switch_theme sometimes may fail because it fires only if the old theme still exists. This is written in the codex.
You can also check it directly in wp-includes/theme.php in the function check_theme_switched() where the action hook is added. You will see that the action hook "after_switch_theme" is inside the condition if ( $old_theme->exists() ) {....}
If you want to be sure the hook fires every time a theme is activated, and no matter if the old theme still exists, you can create your custom hook by hooking the change of the option "stylesheet".
Every time a theme is activated that option stores the name of the new active theme. So:
add_action( 'update_option_stylesheet','my_theme_activation_hook',20,3 );
add_action( 'update_site_option_stylesheet','my_theme_activation_hook',20,3 ); //For multisite installations
function my_theme_activation_hook( $old_value, $value, $option ){
//It adds an action hook after theme activation, no matter if the old theme still exists
do_action( 'my_after_theme_activation');
}
Then you can use your action hook "my_after_theme_activation" or whatever you want to call it.
This method is not perfect because a plugin could also update the option "stylesheet" without a real theme activation. I don't see why they should do it, but it's allowed, and you never know. So, I would take that into account.
Use it if for you it's not a problem that it fires also if a new theme is not really activated, but one of the plugins just changed the option "stylesheet".
You could also directly hook the change of the option "theme_switched" instead of "stylesheet". Not tested this, but looking at the code it looks like it fires two times when you activate a new theme. The first time to save the old theme stylesheet, and a second time to save the value "false".